导读:两个对象间的原型关系类似继承:每个对象都可以把另一个对象作为它的原型,并继承原型的所有属性。对象通过内部属性[[prototype]]指定它的原型。每隔对象都有这个属性,而它也可以是null。通过[[prototype]]属性连接成的原型成为原型链。
(1) 继承
var proto = { describe : function () { return 'name : ' + this.name; } }; var obj = { __proto__ : proto, name : 'obj' }; console.log(obj.describe); // function()
obj继承了describe。你可以访问这个属性,就像对象本身拥有该属性一样。
当你通过obj访问属性时,JavaScript首先从本对象中查找,接着是它的原型,以及原型的原型,以此类推。原型链的行为好像是一个单独的对象。当你调用一个方法时,容易出错是因为this的值总是开始查找方法时所在的那个对象,而不是找到方法时所在的对象。
在describe()中,this是obj,它允许访问obj.name。
(2) 覆写
在一个原型链中,一个对象的属性可以覆写“之后”对象的相同键的属性:前者的属性最先被找到。它隐藏了后者的属性,这样后者的属性就不能被访问了。
obj.describe = function () { return 'overridden'; }; console.log(obj.describe()); // overridden
(3) 通过原型在对象间共享数据
原型对于对象间数据共享十分有用:多个对象可以有相同的原型,这个原型持有所有的共享属性。例如:
var PersonData = { describe : function () { return 'name : ' + this.name; } }; var Alice = { name : 'Alice', __proto__ : PersonData }; var Bob = { name : 'Bob', __proto__ : PersonData }; console.log(Alice.describe()); // name : Alice console.log(Bob.describe()); // name : Bob
(4) 获取和设置原型
① 使用给定prototype创建新对象
调用方法: Object.create(proto,propDescObj?)
② 读取对象原型
调用方法: Object.getPrototypeOf(obj),返回obj的原型。
③ 检查一个对象是否是另一个对象的原型
调用方法: Object.prototype.isPrototypeOf(obj),检查方法的接收者是否是obj的(直接或间接)原型。换句话说,接收者和obj是否在同一原型链上,且obj是否在接受者之前。
④ 特殊属性__proto__
某些JavaScript引擎有特殊属性可以获取和设置对象的原型:__proto__。这样就可以直接访问[[prototype]]。
var obj = {}; console.log( obj.__proto__ === Object.prototype ); // true
关于__proto__,你需要知道以下几点:
1. __proto__读作“dunder proto”,“double underscore proto”的缩写。
2. __proto__不属于ECMAScrip5标准。因此,你如果希望代码遵循这个标准,那么就不能使用__proto__。
3. 然而,越来越多的引擎开始支持__proto__,而它也将成为ECMAScrip6的一部分。
4. 下面的表达式检测引擎是否支持__proto__:
Object.getPrototypeOf({__proto__ : null }) === null;
(5) 设置和删除仅影响自有属性
① 设置属性
原型属性会由多个对象共享。这种方式不会让我们破坏、“改变”原有属性,而只是影响当前对象。
② 删除继承的属性
你只能删除自有属性,而不能删除继承属性。
③ 在原型链的任何位置改变属性
如果你希望改变继承的属性,首先就是找到拥有这个属性的对象,然后改变这个对象的相应属性。
(6) 遍历和检测属性
遍历和检测属性的相关操作受如下情况影响。
1. 继承(自由属性和继承属性)
一个对象的自有属性直接存储在该对象中。继承的属性存储在该对象的其中一个原型中。
2. 枚举(枚举属性和非枚举属性)
属性的枚举是一个特性,标识为true或false。① 列出自有的属性键
你可以列出所有自有的属性键,也可以只列出可枚举的属性键
Object.getOwnPropertyNames(obj):返回obj的所有自有的属性键。
Object.keys(obj):返回所有可枚举的属性键。
注:属性通常都是可枚举的,因此你可以使用Object.keys(),特别是对已创建的对象。
② 列出所有的属性键
如果你想列出所有的属性键(包括自有的和继承的),有两个选择。
第一种就是使用for-in循环。
第二种就是自己实现一个函数,遍历所有属性键(不仅是可枚举的)。
后面写的东西可以参考《JavaScript权威指南》,暂时没有看到哪里有使用到,所以暂时就不看了。