构造函数、原型和实例之间的关系
关系图:
原型链的基本概念
基于上述关系图的理解,让原型对象等于另一个类型的实例,假如这个类型的原型又等于另一个类型的实例,这样层层递进,构成了实例和原型的链条。
关系图:
原型链的代码实现的基本模式
//组合构造函数模式和原型模式
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue()); //true
console.log(instance.constructor === SuperType); //true
console.log(SubType.prototype.constructor === SuperType); //true
SubType继承了SuperType。继承是通过创建SuperType实例,然后赋值给SubType.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例。
代码关系图:
关系结果:instance指向SubType的原型,Sub-Type的原型又指向SuperType的原型。
注意两点:
- getSuperValue()方法仍然还在SuperType.prototype中,但property则位于Sub-Type.prototype中。这是因为property是一个实例属性,而get-SuperValue()则是一个原型方法。既然SubType.prototype现在是SuperType的实例,那么property当然就位于该实例中了。
- instance.constructor现在指向的是SuperType。原因:SubType 的原型指向了另一个对象——SuperType 的原型,而这个原型对象的constructor 属性指向的是SuperType。
通过实现原型链,本质上扩展了原型搜索机制。调用instance.getSu-perValue()会经历三个搜索步骤:
- 搜索实例;
- 搜索Sub-Type.prototype;
- 搜索SuperType.prototype,最后一步才会找到该方法。
原型链的最顶层
所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。
继承关系图(完整版):
SubType继承了SuperType,而SuperType了继承Object。当调用instance.toString()时,实际上调用的是保存在Object.prototype中的那个方法。
确定原型和实例的关系
instanceof操作符和isPrototypeOf()方法
//instanceof操作符
console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
consolo.log(instance instanceof SubType); //true
//isPrototypeOf()方法
console.log(Object.prototype.isPrototypeOf(instance)); //true
console.log(SuperType.prototype.isPrototypeOf(instance)); //true
console.log(SubType.prototype.isPrototypeOf(instance)); //true
子类型定义方法注意
- 重写父类方法或定义新方法注意:给原型添加方法的代码一定要放在替换原型的语句之后。为什么?因为,继承的本质就是重写子类的prototype,如果写在继承前面,那么后面创建实例的时候就访问不到新添加或修改的方法了。
- 在通过原型链实现继承时,不能使用对象字面量创建原型方法。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承SuperType,这个在前
SubType.prototype = new SuperType();
//子类添加父类没有的方法,在后
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
//重写父类方法,在后
SubType.prototype.getSuperValue = function() {
return false;
};
var instance = new SubType();
console.log(instance.getSuperValue()); //false
var instanceSuper = new SuperType();
console.log(instanceSuper.getSuperValue()); //true
由上述结果可以看出:子类重写父类方法,只是屏蔽,原方法不变。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承
SubType.prototype = new SuperType();
//字面量定义方法会使上一句代码无效
SubType.prototype = {
getSubValue: function() {
return this.subproperty;
},
someOtherMethod: function() {
return false;
}
};
var instance = new SubType();
console.log(instance.getSuperValue()); //error
上述继承后字面量写原型对象的方法会导致下面的错误是因为:现在的原型包含的是一个Object的实例,而非SuperType的实例,因此我们设想中的原型链已经被切断,现在的SubType和SuperType没关系了。
原型链问题
- 包含引用类型值的原型;
- 在创建子类型的实例时,不能向超类型的构造函数中传递参数。
//第一个问题
function SuperType() {
this.colors = ["blue", "red", "yellow"];
}
function SubType() {
}
//继承
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"blue,red,yellow,black"
var instance2 = new SubType();
console.log(instance2.colors); //"blue,red,yellow,black"
instance2的colors输出和instance1的colors一样,是因为这属性不是他们自己的,是SuperType实例的,不是他们本身的。
相关推荐
ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用 __proto__ 属性来表示一个对象的原型链。当查找一个...
ECMAScript对象概述(原型链Prototype Chain) ECMA-262主要术语 ECMAScript执行环境(作用域链Scope Chain,闭包机制) ECMAScript函数(new原理) ECMAScript内部属性(参考) ECMAScript执行环境作用域链图示 ECMA-262...
当初ECMAscript的发明者为了简化这门语言,同时又保持继承的属性,于是就设计了这个链表。。 在数据结构中学过链表不,链表中有一个位置相当于指针,指向下一个结构体。 于是乎__proto__也一样,每当你去定义一个...
相信小伙伴们都知道到原型链继承(ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法),因为原型链继承非常的强大,但是也有它的缺点,接下来咱们就按照上面的维度看看原型链继承到底是什么鬼 ...
本文全面讲述了JS继承分类、原理与用法。分享给大家供大家参考,具体如下: 许多 OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承...ECMAScript 中描述了原型链的概念,并将
ECMAScript只支持实现继承,而且实现继承主要依靠原型链来实现。 下面介绍几种js的继承: 原型链继承 原型链继承实现的本质是重写原型对象,代之以一个新类型的实例。代码如下: function SuperType() { this....
在ECMAscript中描述了原型链的概念,并将原型链作为实现继承的主要方法,其基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。 构造函数和原型还有实例之间的关系: 每个构造函数都有一个原型...
1其实是错的,Object这个原型链尽头的对象它没有原型。可是为了更简单表述。在看原型链后你就会明白.toString()这类没有定义过的方法是怎样来的。 上面说的二义性,是文字理解上的,语法本身没有歧义。prot
大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现,下文给大家技术js实现继承的六种方式,需要的朋友参考下
ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。 1.使用对象字面量定义对象 var person={}; 使用这种方式创建对象时,实际上不会调用Object构造函数。 开发人员更喜欢对象字面量的语法。 2...
5.强大的原型和原型链 6.S.O.L.I.D五大原则之单一职责SRP 7.S.O.L.I.D五大原则之开闭原则OCP 8.S.O.L.I.D五大原则之里氏替换原则LSP 9.根本没有“JSON对象”这回事! 10.JavaScript核心(晋级高手必读篇) 11.执行上...
本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点 ECMAscript语言规范来使读者可以更深入的理解闭包。闭包是Closure, 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
原型和原型链 作用域,闭包和内存 事件循环 框架 vue 基本使用 组件 高级特性 周边工具(vuex,vue-router) 原理 react 基本使用 高级特性 原理 周边工具(redux,react-redux,react-router) vue和react对比 性能...
深入理解JavaScript系列(5):强大的原型和原型链 深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP 深入理解JavaScript系列(7):S.O.L.I.D五大原则之开闭原则OCP 深入理解JavaScript系列(8):...
数据类型、运算、对象、Function、继承、闭包、作用域、原型链、事件、RegExp、JSON、Ajax、 DOM、BOM、内存泄漏、跨域、异步装载、模板引擎、前端MVC、路由、模块化、Canvas、ECMAScript 6、Nodejs、编程规范 其他...
[特性] * 如果指定且未定义,则其可枚举的自身属性(即,在其自身上定义的那些属性,而不是其原型链上不可枚举的属性)的对象会指定要添加到新创建的对象中的属性描述符,以及相应的属性名称。 例子import create ...
深入理解JavaScript系列(5):强大的原型和原型链 深入理解JavaScript系列(6):S O L I D五大原则之单一职责SRP 深入理解JavaScript系列(7):S O L I D五大原则之开闭原则OCP 深入理解JavaScript系列(8):...
ECMAScript 5 JSLint Console 第2章 基本技巧 编写可维护的代码 尽量少用全局变量 for循环 for-in循环 不要增加内置的原型 SWitch模式 避免使用隐式类型转换 使用parseInt()的数值约定 ...
ECMAScript JSLint Co ole 第2章 基本技巧 编写可维护的代码 尽量少用全局变量 for循环 for-in循环 不要增加内置的原型 SWitch模式 避免使用隐式类型转换 使用pa eInt()的数值约定 编码约定 命名约定 编写注释 ...