原型

# 原型

# [[Prototype]]

对于默认的 [[Get]] 操作来说,如果无法在对象本身找到需要的属性,就会继续访问对象 的 [[Prototype]] 链

Object.create(..) 的原理

它会创建一个 对象并把这个对象的 [[Prototype]] 关联到指定的对象。

任何可以通过原型链访问到的属性都会被枚举。

使用 in 操作符来检查属性在对象 中是否存在时,同样会查找对象的整条原型链

Object.prototype

所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。

.toString().valueOf()

.hasOwnProperty(..)

.isPrototypeOf(..)
1
2
3
4
5

属性设置和屏蔽

在于原型链上层时 myObject.foo = "bar" 会出现的三种情况

大多数开发者都认为如果向 [[Prototype]] 链上层已经存在的属性([[Put]])赋值,就一 定会触发屏蔽,但只有一种情况是这样

Object.defineProperty(..)

修改委托属性时一定要小心

# “类”

为什么一个对象需要关联到另一个对象?这样做有什么好处?

所有的函数默认都会拥有一个 名为 prototype 的公有并且不可枚举的属性,它会指向另一个对象

Object.getPrototypeOf( a ) === Foo.prototype; // true
1

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
1
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
})
1
2
3
4
5
6

# (原型)继承

Bar.ptototype = Object.create( Foo.prototype );

Object.setPrototypeOf( Bar.prototype, Foo.prototype );
1
2
3
// 在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?
a instanceof Foo; // true

//  a 的整 条 [[Prototype]] 链中是否出现过 Foo.prototype ?
Foo.prototype.isPrototypeOf( a ); // true
1
2
3
4
5

对象的 [[Prototype]] 链。在 ES5 中,标准的方法是:

Object.getPrototypeOf( a )

Object.getPrototypeOf( a ) === Foo.prototype; // true
1
2
3
Object.defineProperty( Object.prototype, '__proto__', {
 get: function() {
  return Object.getPrototypeOf(this);
 },
 set: function(o) {
  Object.setPrototypeOf(this, o);
  return o;
 }
})
1
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();
 }
}
1
2
3
4
5
6
7

在 ES6 中有一个被称为“代理”(Proxy)的高端功能,它实现的就是“方法 无法找到”时的行为。

# 小结

虽然这些 JavaScript 机制和传统面向类语言中的“类初始化”和“类继承”很相似,但 是 JavaScript 中的机制有一个核心区别,那就是不会进行复制,对象之间是通过内部的 [[Prototype]] 链关联的。

对象之间的关系不是复制而是委托

上次更新: 2022/8/8 下午5:26:18