说到原型,肯定离不开对象,在JS中,我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
prototype
函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型。
__proto__
这是每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型。
示例如下:
var obj = new Object()
console.log(obj.__proto__ === Object.prototype) // true
原型的原型
原型是一个对象,既然是对象,我们就可以用最原始的方式创建它,那就是:
var obj = new Object();
obj.name = 'Juff'
console.log(obj.name) // Juff
其实原型对象就是通过 Object 构造函数生成的,实例的 __proto__ 指向构造函数的 prototype
原型链
在 ECMAScript 中,每个由构造器创建的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference),这个引用称之为 原型(prototype)。进一步,每个原型可以拥有指向自己原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的 原型链(prototype chain)
可以在浏览器控制台下一直打印自己的原型,返回的都是一样的。
原型链的定义是这样的:
下面我们看一下实现原型链的一个例子:
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
}
function SubType() {
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SuperType.prototype.getSubValue = function () {
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue());
console.log(instance.getSubValue());
例子定义了两个类型:SuperType和SubType,每个类型分别有一个属性和一个方法。它们的主要区别是 SubType 继承了 SuperType ,而继承是通过创建 SuperType 的实例,并将该实例赋给SubType.prototype 实现的。实现的本质是重写原型对象,代之以一个新类型的实例。换句话说,原来存在于 SuperType 的实例中的所有属性和方法,现在也存在于 SubType.prototype 中了。在确立了继承关系之后,我们给 SubType.prototype 添加了一个方法,这样就在继承了 SuperType 的属性和方法的基础上又添加了一个新方法。
实际上,所有的引用类型默认都继承了Object,这个继承也是通过原型链实现的。记住,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.peototype。