原型
# 原型
# [[Prototype]]
对于默认的 [[Get]] 操作来说,如果无法在对象本身找到需要的属性,就会继续访问对象 的 [[Prototype]] 链
Object.create(..) 的原理
它会创建一个 对象并把这个对象的 [[Prototype]] 关联到指定的对象。
任何可以通过原型链访问到的属性都会被枚举。
使用 in 操作符来检查属性在对象 中是否存在时,同样会查找对象的整条原型链
Object.prototype
所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。
.toString() 和 .valueOf()
.hasOwnProperty(..)
.isPrototypeOf(..)
2
3
4
5
属性设置和屏蔽
在于原型链上层时 myObject.foo = "bar" 会出现的三种情况
大多数开发者都认为如果向 [[Prototype]] 链上层已经存在的属性([[Put]])赋值,就一 定会触发屏蔽,但只有一种情况是这样
Object.defineProperty(..)
修改委托属性时一定要小心
# “类”
为什么一个对象需要关联到另一个对象?这样做有什么好处?
所有的函数默认都会拥有一个 名为 prototype 的公有并且不可枚举的属性,它会指向另一个对象
Object.getPrototypeOf( a ) === Foo.prototype; // true
new Foo() 会生成一个新对象,这个新对象的内部链接 [[Prototype]] 关联 的是 Foo.prototype 对象
new Foo() 这个函数调用实际上并没 有直接创建关联,这个关联只是一个意外的副作用。
Foo.prototype 默认有一个公有并且不可枚举的属性 .constructor,这个属性引用的是对象关联的函数.
实际上,new 会劫持所有普通函数并用构造对象的形式来调用它。
在 JavaScript 中对于“构造函数”最准确的解释是,所有带 new 的函数调用。
a.constructor === Foo
实际上,.constructor 引用同样被委托给了 Foo.prototype,而 Foo.prototype.constructor 默认指向 Foo。
a.constructor 只是通过默认的 [[Prototype]] 委托指向 Foo
Foo.prototype 的 .constructor 属性只是 Foo 函数在声明时的默认属性
function Foo() {}
undefined
Foo.prototype = {}
{}
var a = new Foo()
undefined
a.constructor === Foo;
false
a.constructor === Object
true
function Doo() {}
undefined
var b = new Doo()
undefined
b.constructor === Doo;
true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Object.defineProperty(Foo.prototype, 'constructor', {
enumerable: false,
writable: true,
configurable: true,
value: Foo
})
2
3
4
5
6
# (原型)继承
Bar.ptototype = Object.create( Foo.prototype );
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
2
3
// 在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?
a instanceof Foo; // true
// a 的整 条 [[Prototype]] 链中是否出现过 Foo.prototype ?
Foo.prototype.isPrototypeOf( a ); // true
2
3
4
5
对象的 [[Prototype]] 链。在 ES5 中,标准的方法是:
Object.getPrototypeOf( a )
Object.getPrototypeOf( a ) === Foo.prototype; // true
2
3
Object.defineProperty( Object.prototype, '__proto__', {
get: function() {
return Object.getPrototypeOf(this);
},
set: function(o) {
Object.setPrototypeOf(this, o);
return o;
}
})
2
3
4
5
6
7
8
9
# 对象关联
[[Prototype]] 机制就是存在于对象中的一个内部链接,它会引用其他 对象。
Object.create(null) 会 创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]] 链接的对象,这个对象无法进行委托。由于这个对象没有原型链,所以 instanceof 操作符(之前解释过)无法进行判断,因此总是会返回 false。 这些特殊的空 [[Prototype]] 对象通常被称作“字典”,它们完全不会受到原 型链的干扰,因此非常适合用来存储数据。
Object.create(..) 是在 ES5 中新增的函数
polyfill 代码
if (!Object.create) {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
}
}
2
3
4
5
6
7
在 ES6 中有一个被称为“代理”(Proxy)的高端功能,它实现的就是“方法 无法找到”时的行为。
# 小结
虽然这些 JavaScript 机制和传统面向类语言中的“类初始化”和“类继承”很相似,但 是 JavaScript 中的机制有一个核心区别,那就是不会进行复制,对象之间是通过内部的 [[Prototype]] 链关联的。
对象之间的关系不是复制而是委托