对象关联
- • 现在我们了解了
[[Prototype]]
机制就是存在于对象中的一个内部链接,他会引用到其他对象。 - • 何为原型链?
- • 如果在对象上没有找到需要的属性或方法引用,引擎就会先会在当前对象中查找,如果找不到,就在
[[Prototype]]
关联的对象进行查找。如果后者也没有找到需要的引用就会继续查找它的[[Prototype]]
,直到Object.prototype
为止。以此类推,这一系列的对象链接被称为 "原型链"。
创建关联
- • 那
[[Prototype]]
机制的意义是什么?为什么要创建这些关联呢? - • 如下代码:
var foo = { something: function(){ console.log('do something'); } }; var bar = Object.create(foo); var.something(); // do something
- • 使用
Object.create() 创建了一个新对象且关联到 foo
,这样就可避免一些不必要的麻烦(比如使用 new 的构造函数调用会生成 .prototype 和 .constructor 引用) - • 注意:
Object.create(null) 会创建一个空链接的对象,因为是空的,所有无法进行委托,并且由于这个对象没有原型链,在使用 instanceof 时也就无法进行判断,因此他们总是会返回 false。
- • 在上述的代码中我们通过创建一个新的类来创建两个对象之间的关系,其实并不需要这么做,只需要通过委托关系来关联对象就足够了。
// Object.create()的 polyfill 代码 if(Object.create){ Object.create = function(o){ function F(){}; F.prototype = o; return new F(); } }
- • 上述代码使用一个一次性函数 F, 通过改写它的 .prototype 属性使其指向想要关联的对象,然后再使用 new F() 来构造一个新对象进行关联。
- • Object.create() 的扩展:
var anotherObject = { a:2 }; var myObject = Object.create( anotherObject, { b: { enumerable: false, writable: true, configurable: false, value: 3 }, c: { enumerable: true, writable: false, configurable: false, value: 4 } }); myObject.hasOwnProperty( "a" ); // false myObject.hasOwnProperty( "b" ); // true myObject.hasOwnProperty( "c" ); // true myObject.a; // 2 myObject.b; // 3 myObject.c; // 4
- • Object.create() 的第二个参数指定了需要添加到新对象中的属性名以及这些属性的属性描述符。
小结
- 1. 当访问对象中不存在的一个属性时,[[Get]] 操作就会查找对象内部
[[Prototype]]
关联的对象,这个关联关系就是一条 "原型链"(有点像嵌套的作用域),在找到属性时会对它进行遍历。 - 2. 所有普通对象都有内置的 Object.prototype,指向原型链的顶端(比如说全局作用域), 如果在原型链中找不到指定的属性就会停止。
- 3. 关联两个对象最常用的方法就是用 new 关键字进行函数调用,在调用的第四个步骤中会创建一个关联到创建的新对象。
- 4. 使用 new 调用函数时会把新对象的 .prototype 属性关联到其他对象,带 new 的函数调用被称为构造函数调用
- 5. 对象之间是通过
[[Prototype]]
链关联的。 - 6. Object.create(null) 会创建一个空链接的对象,因为是空的,所有无法进行委托,并且由于这个对象没有原型链,在使用 instanceof 时也就无法进行判断,因此他们总是会返回 false。
- 7. 如果对象中的属性不直接存在于当前对象中而是存在于原型链上层时会出现三种情况:
- 1. 如果在
[[Prototype]]
原型链上层存在对象中的属性访问属性,并且没有被标记为只读(writable: false)
,那就会直接在当前对象中添加一个对象中的属性属性,则它是屏蔽属性。 - 2. 如果在
[[Prototype]]
原型链上存在对象中的属性属性,但是被标记为只读, 那就无法修改已有属性或在当前对象上创建屏蔽属性。如果在严格模式下运行,会直接抛出一个错误。否则,这条赋值语句就会被忽略。总之,不会发生屏蔽。 - 3. 如果在
[[Prototype]]
原型链上层存在对象中的属性并且它是一个setter
,那就一定会调用这个setter
。对象中的属性不会被添加到(可以说屏蔽到)当前对象中,也不会重新定义对象中的属性这个setter
。
- 8. 使用
for...in
遍历对象和in
操作符时都会查找对象的整条原型链
。(无论属性是否可枚举) - 9. 一个类其实就是一张蓝图,只是一个计划,并不是真正的可以交互的对象,我们必须通过实例化来调用所有公有数据属性,而这个
实例化对象就是类的所有特性的一份副本
。 - 10. 多态:父类的一些通用行为可以被子类的行为重写。
- 11. 多态并不表示父类和子类有关联,子类得到只是父类的一个副本,类的继承就是复制。
特殊字符描述
•问题标注 Q:(question)
•答案标注 R:(result)
•注意事项标准:A:(attention matters)
•详情描述标注:D:(detail info)
•总结标注:S:(summary)
•分析标注:Ana:(analysis)
•提示标注:T:(tips)