原型链是用于在现有对象的基础上构建新类型的对象。它类似于基于类的语言中的继承。
对象实例的原型可以通过 Obeject.getPrototypeOf(object) 或 proto 属性获得,而构造函数的原型可通过 Object.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;
};
let instance = new SubType();
console.log(instance.getSuperValue()); // true
复制代码
默认情况下,所有引用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。
2. 原型与继承关系
原型与实例的关系可以通过两种方式来确定。第一种方式是使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true。
确定关系的第二种方式是使用 isPrototypeOf() 方法。原型链中的每个原型都可以调用这个方法。
// 只要原型链中包含这个原型,这个方法就返回true
console.log(Object.prototype.isPrototypeOf(instance)); // true
复制代码
3. 关于方法
子类有时候需要覆盖父类的方法,或者增加父类没有的方法。这些方法必须在原型赋值之后再添加到原型上。
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;
};
let instance = new SubType();
console.log(instance.getSuperValue()); // false
复制代码
重点:如果以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链。
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() {
return this.subproperty;
},
someOtherMethod() {
return false;
}
};
let instance = new SubType();
console.log(instance.getSuperValue()); // 出错
复制代码
原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会在原型上的原因。
在使用原型实现继承时,原型实际上变成了另一个类型的实例。(原先的实例属性变成了原型属性)
function SuperType() {
this.colors = ["red", "blue", "green"];
}
function SubType() { }
// 继承SuperType
SubType.prototype = new SuperType();
let instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // "red,blue,green,black"
let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black"
复制代码
原型链的第二个问题:子类型在实例化时不能给父类型的构造函数传参。
未完结!更多内容尽情期待下一节~