原型(prototype)
在JavaScript中,原型(prototype)也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个prototype
内部属性,这个属性所对应的就是该对象的原型。
prototype
作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了 __ proto__ 这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器 Object.getPrototype(object))。在JavaScript的原型对象中,还包含了一个constructior
属性,这个属性对应创建所有指向改原型的实例的构造函数。
原型(prototype)作用
通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
JavaScript规定,每个函数都有一个
prototype
属性,指向一个对象。
function f() {}
typeof f.prototype // "object"
上面代码中,函数f默认具有prototype属性,指向一个对象。
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
function Animal(name){
this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('大猫');
var cat2 = new Animal('二猫');
cat1.color // 'white'
cat2.color // 'white'
上面代码中,构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象。
原型对象上天骄一个color属性,结果实例对象都共享了该属性。
原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
Animal.prototype.color = 'yellow';
cat1.color // 'yellow'
cat2.color // 'yellow'
上面代码中,原型对象的color属性的值变为yellow,两个实例对象的color属性立刻跟着变了。
这是因为实例对象其实没有color属性,都是读取原型对象的color属性。
也就是说,当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。这就是原型对象的特殊之处。
如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
cat1.color = 'black';
cat1.color //'black'
cat2.color // 'yellow'
Animal.prototype.color //'yellow'
上面代码中,实例对象cat1的color属性改为black,就使得它不再去原型对象读取color属性,后者的值依然为yellow。
原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
原型链
原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链(prototype chain)。
- 构造函数、原型和实例的关系:
每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(prototype),而实例则包含一个指向原型对象的内部指针(__ proto __)。
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
注意,一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
_ proto_ 和 prototype的区别是?
一句话:_ proto_是对象的属性;prototype是函数的属性
- 不能断章取义,_ proto_ 和 prototype只是两个key而已
- 我们一般研究对象的__ proto__和函数的prototype
- 对象.__ proto__ === 某函数.prototype
- 如果把函数看成对象,那么函数.__ proto__ === Function.prototype
- 如果把 Function 看成对象,那么 Function.__ proto__ === Function.prototype
- Function.prototype._ proto_ == Object.prototype
文章著作权归饥人谷_sunny和饥人谷所有,转载须说明来源