原型链是ECMAScript的主要继承方式。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
/**
* 继承SuperType
* SubType通过创建SuperType的实例,
* 并将其赋值给自己的原型SubType.prototype,
* 从而实现了对SuperType的继承。
*
* 赋值重写了SubType最初的原型,将其替换为SuperType的实例
*/
SubType.prototype = new SuperType();
// 所有原型对象自动获得一个名为constructor的属性,指回与之关联的构造函数
console.log(SubType.prototype.constructor); // [Function: SuperType]
console.log(SubType.prototype.constructor === SuperType); // true
// 每次调用构造函数创建一个新实例,这个实例的内部[[Prototype]]指针就会被赋值为构造函数的原型对象
console.log(SubType.prototype.__proto__); // SuperType { getSuperValue: [Function] }
console.log(SubType.prototype.__proto__ === SuperType.prototype); // true
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
let instance = new SubType();
// isProotypeOf()会在传入参数的[[Prototype]]指向调用它的对象时返回true
/**
* SubTye的实例instance不仅能动SuperType的实例中继承属性和方法,而且还与SuperType的原型Super.prototype挂上钩
* 于是instance(通过内部的[[Prototype]])指向SubType.prototype,
* 而SubType.protoytpe(作为SuperType的实例又通过内部的[[Prototype]])指向SuperType.prototype
*/
console.log(SubType.prototype.isPrototypeOf(instance)); // true
console.log(SuperType.prototype.isPrototypeOf(instance)); // true
// Object.getPrototypeOf(),返回参数的内部特性[[Prototype]]的值
console.log(Object.getPrototypeOf(instance)); // SuperType { property: true, getSubValue: [Function] }
console.log(Object.getPrototypeOf(SubType)); // [Function]
console.log(Object.getPrototypeOf(SubType.prototype)); // SuperType { getSuperValue: [Function] }
// 由于SubType.prototype的constructor属性被重写为指向SuperType,所以instance.constructor也指向SuperType
console.log(instance.constructor === SuperType); // true
/**
* SubType的实例调用了它继承的getSuperValue()方法。
* 调用instance.getSuperValue()经过了3步搜索:
* instance、SubType.prototype和SuerType.prototype。
* 对属性和方法的搜索会一直持续到原型链的末端
*/
console.log(instance.getSuperValue()); // true
console.log(instance.getSubValue()); // false
1、默认原型:
默认情况下,所有引用类型都继承自Object,任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。
2、原型与继承关系:
原型与实例的关系可以通过两种方式来确定:
① instanceof 操作符;② isPrototypeOf() 方法。
3、关于方法:
子类要覆盖父类方法,或者要添加父类没有的方法,必须在原型赋值之后在添加到原型上。
以对象字面量创建的原型方法会破坏之前的原型链,相当于重写了原型链,覆盖后的原型是一个Object的实例。
4、原型链的问题:
(1)属性通常会在构造函数中定义而不会在原型上,因为原型中包含的引用值会在所有实例之间共享;
(2)子类型在实例化时不能给父类型的构造函数传参。