JavaScript Core -- 继承机制

React Native Text组件底层原理与真机渲染全链路解析 React Native中的Text组件远不止是文本容器,而是连接JavaScript层与原生渲染器的关键枢纽。其核心原理涉及声明式UI、Bridge通信协议、平台字体度量差异及样式继承机制。理解Text如何将JSX编译为序列化指令、如何通过measure函数对齐原生intrinsicContentSize、以及state更新如何触发异步原生setText调用,是解决文字截断、行高错位、点击偏移等高频问题的技术前提。尤其在iOS/Android双端适配、SafeArea动态注入、字体加载降级等真实场景中,T 阅读详情


JavaScript 继承机制历史回顾

    javascript最开始被设计为一款运行在浏览器上的简易语言,当时面向对象语言C++/JAVA大行其道。javascript之父 Brendan Eich无疑受到了影响,而且更进一步将javascript中所有的数据类型都设计为了对象(Object)。如果真的作为一种简单易用的语言,其实是不需要拥有“继承”机制的,但是既然JavaScript中都是对象,那怎么将所有的对象联系到一起呢?咳咳,最后Brendan Eich还是设计了“继承”。

    但他还是不想引入“类”的概念,因为这样会将JavaScript语言变得很正式,提高了入门的难度,他的初衷是一门简单易用的脚本语言而已,最终决定使用new 操作符从原型对象生成一个实例对象。使用new后面跟着的构造函数作为原型对象,如下所示生成一个person的实例person1

    function person(name){
    this.name = name;//this对象代表新创建的实例对象
    }
    var person1 = new Person('feng')
    但是,使用构造函数生成一个实例,有一个缺点那就是无法共享属性和方法,如下所示

   function person(name){
<span style="white-space:pre">	</span>this.name = name;//this对象代表新创建的实例对象
<span style="white-space:pre">	</span>this.species = '哺乳类';
    }   
   var person1 = new person('feng');//this.name = 'feng'
   var person2 = new Person('bling');//this.name = 'bling' 
   person1.species = '爬行类'; 
   alert(person2.species);//哺乳类,不会受person1实例属性的改变而影响

 
      考虑到这一点,Brendan Eich决定引入一个全新的名词“prototype”作为构造器的属性,这个属性指向一个对象prototype(原型对象),这个原型对象包含着对象所有需要共享的属性和方法,而不需要共享的属性和方法则放到了构造器中。
  实例对象一旦创建就自动引入原型对象的属性和方法,属性和方法沿着原型链进行查找
  。还是上面那个例子修改一下,如下所示 
  

    function person(name){
<span style="white-space:pre">	</span>this.name = name;//this对象代表新创建的实例对象
    }
    person.prototype = {
        species :'哺乳类'
    }
    var person1 = new person('feng');//this.name = 'feng'
    var person2 = new person('bling');//this.name = 'bling'
    alert(person1.species);//哺乳类
    alert(person2.species);//哺乳类
	
    这样所有的实例对象就“继承了”原型对象中的属性和方法,通过实例对象的原型。


JavaScript 继承实现原理

初入江湖:原型继承

    构造函数(类)的原型带有一个 constructor 属性,指回构造函数(如果重新分配了原型指针,需要手动添加 constructor 属性,重新建立构造函数和原型对象之间的联系)。构造函数的实例上会自动生成一个属性指向该类原型(在Chrome上可以通过“__proto__”访问到该对象,而IE上该属性则是不可见的), 而形成了一条原型链(Prototype-chain),如下图

    JavaScript将原型链作为实现继承的主要方法。当代码读取某个对象的某个属性的时候,都会按照上图中存在的实现执行一遍搜索,目标是具有给定名字的属性。搜索首先从对象实例开始,如果在实例中找到该属性则返回,如果没有则查找prototype,如果还是没有找到则继续递归prototype的prototype对象,直到找到为止,如果递归到object仍然没有则返回错误。同样道理如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。搜索时的这个路线抽象成为了所谓的原型链。

 注:写一个函数来判断定属性属于原型中还是存在于对象中

function hasPrototypeProperty(object,name){  
    return !object.hasOwnPrototype(name) &&( name in object);   
}  

    name in object->只要name能被访问,就返回true,无论远行中还是对象中;object.hasOwnPrototype(name)->对象本身拥有name属性返回true。所以,当name属性存在于原型中时,函数返回true

    修改原型对象的属性时,那么所有的实例通过原型链都会访问到更改后的属性;但是如果将原型对象设置为其他值Person.prototype = {},那么原来的实例person1和原来的原型对象的关系没有变化,person1还拥有原来原型对象的属性 ,直接修改prototype属性不会影响已经创建的属性,影响的将是新创建的实例

    下面演示代码的基本原理是利用原型让一个subType引用superType的属性和方法。将subType的prototype属性设为superType的实例,这时候subType的原型链中就包含了superType的属性和方法,大致是这样的

    function SuperType(){
        this.property=true;
    }

    SuperType.prototype.getSuperValue=function(){
        return this.property;
    };

    function SubType(){
        this.subProperty=false;
    }

    SubType.prototype=new SuperType();//让subType的原型指向SuperType的原型

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    这样SubType就实现了对SuperType的继承,看个图

image


(原型中的construnctor属性指回那个构造函数)

    验证一下,是不是这个样子

    var instance=new SubType();
    console.log(instance.getSuperValue()); //true
    console.log(instance.getSubValue()); //false
    console.log(instance instanceof SuperType); //true
    console.log(instance instanceof SubType); //true

    果不其然,SubType的实例同时也是SuperType的实例,可以访问到SuperType的属性和方法,实现了SubType对SuperType的继承。在上面的代码中SubType没有使用其默认的prototype对象,而是使用了SuperType的实例,这样SubType的实例拥有

        1.SuperType实例的属性和方法

        2.SuperType的prototype的属性和方法(如上图,在原型链中SuperType的实例有指向SuperType的prototype的指针)

        3.SubType实例属性和方法(subProperty)

        4.SubType新的prototype对象追加的属性和方法(getSubValue)

    熟悉JavaScript的同学肯定清楚:和很多强类型面向对象语言一样,JavaScript的所有引用类型都默认继承自Object对象,这个继承也是通过原型链实现的。

        image

    所有函数都是Object对象的实例,这样是不是明白了为什么所有自定义类型都会用于toString, valueOf 等默认方法了吧,看起来很不错,但是这样的继承方式有两个需要注意的地方

    1.给子类型的prototype对象内追加方法和属性必须在继承了父类型实例之后,否则追加的方法、属性会被重写,也就是说上面的例子

    function SubType(){
        this.subProperty=false;
    }

    SubType.prototype=new SuperType();

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

不能写成这样

    function SubType(){
        this.subProperty=false;
    }

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }
    
    SubType.prototype=new SuperType();

2.子类型的prototype不能通过字面量赋值,这样也会重写原型链而不是追加,也就是说不能写成这样

    function SubType(){
        this.subProperty=false;
        }

    SubType.prototype=new SuperType();

    SubType.prototype={
        getSubValue:function(){
            return this.subProperty;
        }
    }


名动一方:组合继承

    上面的经典继承方式是不完美的,当父类型中存在引用类型的属性的时候,子类型的所有实例会共享这些属性,一处修改,处处更新,这样是不安全的

   function SuperType(){
        this.property=true;
        this.colors=['red','blue','green'];
    }

    SuperType.prototype.getSuperValue=function(){
        return this.property;
    };

    function SubType(){
        this.subProperty=false;
    }

    SubType.prototype=new SuperType();

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    var sub1=new SubType();
    sub1.colors.push('yellow');
    var sub2=new SubType();
    console.log(sub2.colors);//["red", "blue", "green", "yellow"]

      确实是这样的,但是这个错误很熟悉的赶脚有没有,在javascript创建对象的过程中也会有这个问题。解决方法:子类型构造函数中引入父类型的构造函数,使实例拥有自己独有的属性

    function SuperType(){
        this.property=true;
        this.colors=['red','blue','green'];
    }

    SuperType.prototype.getSuperValue=function(){
        return this.property;
    };

    function SubType(){
        this.subProperty=false;
       <span style="color:#ff0000;"> SuperType.call(this);</span>
    }
    SubType.prototype=new SuperType(); 
    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    var sub1=new SubType();
    sub1.colors.push('yellow');
    var sub2=new SubType();
    console.log(sub2.colors);//["red", "blue", "green"]

    这样在子类的构造函数中调用父类的构造函数,这样的写法实际上是在新创建的SubType的实例环境下调用SuperType的构造函数,实例中执行SuperType函数中对象初始化代码,Subtype的每个实例就会有自己的colors副本了。这样的继承方式在坊间被称为组合式继承。(额,你是否联想到了java中的super()...,一样的道理)

    这样做还多了个好处,可以传递参数了

    function SuperType(name){
        this.property=name;
        this.colors=['red','blue','green'];
    }

    SuperType.prototype.getSuperValue=function(){
        return this.property;
    };

    function SubType(name){
        this.subProperty=false;
        SuperType.call(this,name);
    }
    SubType.prototype=new SuperType(); 
      //或者将这行代码替换为  
      //SubType.prototype = Object.create(SuperType.prototype);//Object.create创建一个空对象,并且对象的原型指向参数SuperType.prototype
      //SubType.prototype.constructor = SubType//若不设置的话,SubType.prototype会指向SuperType

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    var sub1=new SubType('Byron');
    console.log(sub1.property);//Byron


 
  

一代宗师:寄生组合式继承

    看起来使用组合式继承很完美了,但是...总是有但是,使用组合继承总会调用两次父类的构造函数,这样父类的实例属性和方法在子类的实例中会有两份。父类初始化两次,这有时会导致一些问题,举个例子,父类构造函数中有个alert,那么创建子类实例时,会发现有两次弹框。

    function SubType(name){
        this.subProperty=false;
        SuperType.call(this,name); //第一次
    }

    SubType.prototype=new SuperType(); //第二次

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    image

    可以看到子类的原型中也包含了父类的属性,只不过因为解释器的属性查找机制,被子类的属性所覆盖,只要子类的特权成员被删除,原型中相应的成员就会暴露出来:

    问题的根源就是调用两次SuperType的构造函数,其实在第一次调用的时候SubType就已经获得了SuperType的实例属性和方法,第二次调用的时候仅需要SuperType的prototype属性就可以了,因此可以这样写

    function extend(subType,superType){
        var _prototype=new Object(superType.prototype); //得到父类prototype对象副本
        _prototype.constructor=subType; //constructor属性改为子类自己的
        subType.prototype=_prototype; //重写子类prototype
    }

    function SuperType(name){
        this.property=name;
        this.colors=['red','blue','green'];
    }

    SuperType.prototype.getSuperValue=function(){
        return this.property;
    };

    function SubType(name){
        this.subProperty=false;
        SuperType.call(this,name); 
    }

    extend(SubType,SuperType);

    SubType.prototype.getSubValue=function(){
        return this.subProperty;
    }

    image

    未完待续。。。。。。

Open UI5 源代码解析之161:Renderer.js 本文深入解析了OpenUI5项目中sap.ui.core.Renderer的核心功能与实现机制。作为UI5生态中控件渲染的基础设施,Renderer基类实现了控件逻辑与HTML输出的职责分离,提供扩展框架、文本对齐计算、RTL适配等通用工具。文章详细介绍了现代扩展签名Renderer.extend的实现原理,包括继承机制、全局导出策略,并通过代码示例展示了多层继承实践。同时分析了旧签名的兼容性处理、泛型用法场景,以及Renderer与渲染管线的协作关系。最后结合企业设计系统的真实案例,阐述了如何通过渲染器继 阅读详情

相关推荐

Open UI5 源代码解析之221:Component.js

OpenUI5 Component.js 核心功能解析 sap.ui.core.Component 是 OpenUI5 框架的核心组件类,主要提供以下功能: 组件生命周期管理: 通过 runAsOwner() 管理组件所有权 提供 destroy() 方法实现资源释放 Manifest 解析: 支持 getManifest() 获取组件配置 实现配置继承与合并功能 声明式模型装配: 自动处理 manifest 中定义的模型和数据源 支持 OData 和 i18n 等模型类型 提供预加载机制优化性能 组件组合

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 784

在linux系统中编写c程序,【深入学习linux】在linux系统下怎么编写c语言程序并运行...

jquery取checkbox选中的值"){print $4","a[length( ...关于js的对象原型继承&lpar;一&rpar;javascript中,对象的继承是通过原型去继承. 可以这样理解:js中的对象,包含的除了属性和方法,还有一个最基本的原型__proto__对象.这个原型__proto__指向谁,这个对象就继承谁. ...Cookie-base 认证实现(学...

weixin_36372579的博客 247

Open UI5 源代码解析之1132:Tab.js

摘要: Tab.js 是 SAP OpenUI5 中 sap.ui.commons.Tab 控件的实现文件,继承自 Panel 类,用于作为 TabStrip 的单个页签实体。该文件的核心设计体现了框架式开发的特点: 模块化与继承:通过继承 Panel 复用内容容器能力,仅扩展页签特有属性(如 closable、滚动控制),依赖 TabStrip 处理整体布局和交互逻辑。 状态分离:页签的选中态(selected)实际由父容器 TabStrip 管理,体现状态中心化设计,兼容旧版属性以保持向后兼容。 渲染委

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1659

深度解析Reactor.js:Signal信号系统的完整设计与实现指南

Reactor.js是一个**简单而强大的响应式编程库**,它通过Signal信号系统实现了无框架的自动依赖跟踪和数据更新机制。这个轻量级库让开发者能够在不依赖任何框架的情况下,构建响应式的JavaScript应用,是现代前端开发中值得掌握的重要工具。🚀 ## 🔍 Signal信号系统核心概念解析 Reactor.js的核心是Signal信号系统,它由三个关键组件构成: 1. **Sig

gitblog_00740的博客 913

Open UI5 源代码解析之148:ListItem.js

摘要: sap.ui.core.ListItem 是 OpenUI5 核心库中的基础条目类,继承自 sap.ui.core.Item,用于为列表/选择类控件(如 Select、ComboBox)提供标准化的数据容器。它扩展了 icon 和 additionalText 属性,支持图标和辅助文本显示。作为纯数据结构,其渲染由宿主控件处理,确保跨控件库的一致性。典型应用场景包括成本中心选择、供应商筛选等业务界面,通过数据绑定实现动态条目配置。示例代码展示了如何在 Select 和 ComboBox 中通过工厂模

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1017

Open UI5 源代码解析之1118:RatingIndicator.js

《RatingIndicator.js源码分析与设计解读》 摘要: 本文深入分析了SAP OpenUI5项目中RatingIndicator.js评分控件的实现。该文件定义了一个基于sap.ui.core.Control的评分组件,通过元数据设计、交互逻辑和渲染分工实现了完整的评分功能。分析揭示了控件的三层核心设计:1) 属性系统支持数据绑定与业务语义(如可编辑状态、最大值约束、平均分展示);2) 事件与无障碍访问设计确保交互完整性;3) 视觉模式与主题响应机制分离了数据与表现逻辑。特别值得注意的是其状态管

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1881

Open UI5 源代码解析之846:SelectionButtonItem.js

SelectionButtonItem 解析摘要 SelectionButtonItem.js 是 OpenUI5 中 MDC 图表模块的核心元数据载体文件,位于 sap/ui/mdc/chart/ 路径下。该文件定义了一个继承自 sap.ui.core.Element 的轻量级类,主要功能是为图表选择按钮提供配置项支持。 关键特性: 通过 metadata 定义 key/text/tooltip/icon 四个属性 作为可绑定的配置对象,不包含渲染逻辑 支持 UI5 的数据绑定和聚合管理机制 项目中的作用

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 856

Open UI5 源代码解析之219:CommandExecution.js

摘要: CommandExecution 是 OpenUI5 框架中连接业务命令与 UI 交互的关键组件,它通过元数据配置、状态管理和事件分发机制实现命令的统一管理。该组件支持从 manifest 读取命令定义,自动注册快捷键,并通过 $cmd 模型维护命令状态。其核心功能包括:基于 visible 和 enabled 状态的触发控制、父级上下文感知的命令数据维护、以及完整的资源清理机制。在大型企业应用中,CommandExecution 有效解决了命令状态分散、快捷键冲突等问题,为复杂 UI 交互提供了标

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 669

Open UI5 源代码解析之1128:SearchProvider.js

摘要: SearchProvider.js是SAP OpenUI5框架中的一个兼容层文件,位于sap.ui.commons库。该文件主要作为历史遗留代码与新架构之间的桥梁,将旧的SearchProvider功能桥接到新的OpenSearchProvider实现上。文件结构简洁,包含模块声明、类注释、继承定义和一个核心的_doSuggest方法。通过元数据标记为"deprecated",表明它已不建议新代码使用,但仍需保留以支持旧系统升级。该文件体现了大型框架演进中的典型策略:将核心功能下

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 725

Open UI5 源代码解析之722:Column.js

摘要:Column.js 是 OpenUI5 上传模块中的关键控件扩展文件,通过继承 sap.m.Column 并补充上传场景专属元数据,为 UploadSetwithTable 提供表格列个性化能力。该文件采用轻量级设计,仅增加5个业务属性(如列个性化文本、数据路径等),却实现了上传列表的排序、分组和过滤功能。其价值在于:1)通过元数据反射自动生成访问器,减少代码量;2)明确语义边界,限定仅用于上传场景;3)支持企业级个性化需求。该设计体现了框架扩展的克制原则,以最小代码实现最大业务价值,是接口层语义设计

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 36

Open UI5 源代码解析之601:GridDragOver.js

OpenUI5 GridDragOver.js 解析 该文件位于sap.f库的dnd目录,是UI5框架中处理网格容器拖拽交互的核心模块。主要功能包括: 拖拽体验优化:提供稳定的悬停计算、落点建议和视觉反馈,解决快速移动时的抖动问题 网格布局适配:作为sap.f网格化布局的胶水层,连接核心拖拽会话与业务容器,替换默认指示器为网格专用样式 状态管理:通过200ms停留阈值、冻结机制等实现防抖和抗抖动,确保交互稳定性 生命周期控制:处理渲染前后的状态恢复,支持动态列表和模板绑定场景 国际化支持:根据RTL布局自动

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1117

Open UI5 源代码解析之844:Item.js

OpenUI5中的sap.ui.mdc.chart.Item.js文件定义了一个核心元数据类,用于描述图表中的字段属性。作为MDC图表模块的基础构件,它封装了字段名称、标签、类型和角色等关键信息,实现了图表配置与数据属性之间的桥梁功能。该文件采用UI5标准的Element.extend方式定义类,通过metadata.properties配置字段语义,支持propertyKey新属性同时兼容旧name属性,体现了框架演进中的兼容性设计。Item类在MDC图表体系中承担着字段schema的角色,使图表能够自动

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 229

Open UI5 源代码解析之987:Title.js

摘要: sap.m.Title 是 OpenUI5 框架中的核心标题控件,远非简单的文本显示组件。它通过继承 Control 实现完整控件能力,兼具语义层级(level)、视觉样式(titleStyle)和排版控制(换行/断词)。其设计亮点包括: 多源标题整合:支持直接文本、外部关联(sap.ui.core.Title)或复杂内容聚合(content),适应不同场景需求; 语义与视觉分离:独立控制标题的语义级别(如无障碍阅读的 H1)与视觉表现(如大号字体); 企业级特性:内置 RTL 支持、长文本处理(自

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 735

Open UI5 源代码解析之828:HorizontalLayout.js

HorizontalLayout.js是OpenUI5框架中的布局控件文件,定义了水平排列子控件的容器组件。该文件采用UI5标准控件开发模式,通过继承sap.ui.core.Control基类实现,将渲染逻辑委托给HorizontalLayoutRenderer。核心功能包括:通过allowWrapping属性控制内容是否允许自动换行;支持content聚合容纳任意子控件;提供无障碍访问支持。该布局控件相比FlexBox等更轻量,适用于表单字段、工具栏等简单水平排列场景,通过设计时元数据支持可视化编辑器拖拽

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2219

Open UI5 源代码解析之347:App.support.js

摘要: App.support.js是OpenUI5框架中用于支持规则检查的关键文件,位于sap.ui.core模块下。该文件包含一系列针对应用层和框架层的诊断规则,主要用于检测废弃API、同步调用、错误继承模式等潜在问题。多数规则自UI5 1.119版本起标记为废弃,表明其过渡性质。文件依赖核心库、视图/控制器模块及jQuery,通过Support Assistant框架执行规则检查,采用主动扫描和日志分析两种机制。典型规则包括同步代码检测、全局API调用检查、jQuery迁移提示等,实际案例显示这些规则

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1481

Open UI5 源代码解析之965:ViewSettingsFilterItem.js

OpenUI5 ViewSettingsFilterItem.js 解析摘要 ViewSettingsFilterItem.js 是 SAP OpenUI5 中 ViewSettingsDialog 筛选体系的核心组件,作为筛选分组的父节点模型。它继承自 ViewSettingsItem,扩展了管理子筛选项的能力,形成层级筛选结构。 关键特性包括: 通过 multiSelect 属性控制子项是否允许多选 items 聚合管理子筛选项集合 事件系统处理结构变化(filterDetailItemsAggrega

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5839

Open UI5 源代码解析之1087:Label.js

OpenUI5 Label.js 摘要分析 sap.ui.commons.Label.js 是 OpenUI5 中的一个基础标签控件实现,主要功能是为其他输入控件提供文字说明和语义标注。该文件具有以下核心特点: 继承体系:基于 sap.ui.core.Control 构建,实现 ToolbarItem 和 Label 接口,支持工具栏集成和无障碍访问 关键属性: design - 控制标签视觉样式(标准/强调) textDirection - 支持国际化文本方向 wrapping - 控制文本自动换行 ic

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1523

Open UI5 源代码解析之1093:HorizontalDivider.js

HorizontalDivider.js 是 SAP OpenUI5 框架中一个已弃用的视觉分隔线控件实现文件,属于 sap.ui.commons 传统桌面控件库。该文件主要功能是通过 Control.extend 注册一个简单的水平分隔线控件,定义了三个核心属性:width(支持CSS尺寸)、type(区分区域/页面级分隔)和 height(控制留白档位)。作为典型的元数据驱动型控件,它将渲染逻辑委托给配套的 Renderer 模块,自身仅负责声明控件结构和配置项。该控件现已被标记为弃用,推荐使用更现代的

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 688
上一篇: JavaScript Core -- 垃圾回收机制
下一篇: JavaScript Core -- 包装对象
阿懒先生
博客等级 码龄15年 12粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值