【JS】《你不知道的JavaScript》 之 原型

js中的对象有一个特殊的[[Prototype]]内置属性,其实就是对于其他对象的引用。

var anotherObj = {a:2}
var myObject = Object.create(anotherObj)
myObject.a   // 2

Object.create()会创建一个对象并把这个对象的[[Prototype]]关联到指定的对象。

属性设置和屏蔽

给一个对象设置属性并不仅仅是添加一个新属性或者修改已有的属性值。

以 myObj.foo = 'bar' 为例看下这个过程:

  1. 如果 myObj 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属性值。
  2. 如果 foo 不是直接存在于 myObj中,[[Prototype]] 链就会被遍历,如果原型链上找不到 foo,foo 就会被直接添加到 myObj上。
  3. 如果属性名 foo 既出现在 myObj 中也出现在 myObj 的 [[Prototype]] 链上层,那么就会发生屏蔽。myObj中包含 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObj.foo 终会选择原型链中最底层的foo属性。

 

‘类’函数

function Foo() {}
var a = new Foo()
Object.getPrototypeOf(a) === Foo.prototype   // true

 new Foo() 的其中一步就是将 a 内部的 [[Prototype]] 链接到 Foo.prototype 所指向的对象。

继承 意味着复制操作,js默认并不会复制对象属性。相反,js会在两个对象之间创建一个关联,这样一个对象就可以通过 委托 访问另一个对象的属性和函数。

 

‘构造函数’

function Foo() {}
Foo.prototype.constructor === Foo   // true
var a = new Foo()
a.constructor === Foo   // true

Foo.prototype 默认有一个共有且不可枚举的属性 constructor ,这个属性引用的是对象关联的函数。但实际上 a 本身并没有 constructor 属性。而且虽然 a.constructor 确实指向 Foo 函数,但是这个属性并不是表示 a 由 Foo ‘构造’。实际上, constructor 引用同样被委托给了 Foo.prototype ,而 Foo.prototype.constructor 默认指向 Foo。

再看看下面的代码:

function Foo () { /* ... */ }

Foo.prototype = { /* ... */ }  // 创建一个新原型对象

var a1 = new Foo()
a1.constructor === Foo   // false
a1.constructor === Object   // true

看起来 Object() 并没有“构造”a1,应该是Foo()“构造”了它。但是并不是这样。

a1并没有 constructor 属性,所以他会委托 [[Prototype]] 链上的 Foo.prototype。但这个对象也没有 constructor 属性(不过默认的 Foo.prototype 对象有这个属性),所以它会继续委托,这次会委托给委托链顶端的 Object.prototype。这个对象有 constructor 属性,指向内置的 Object() 函数。

函数不是构造函数,但是当且仅当使用 new 时,函数调用会变成‘构造函数调用’。

 

对相关联

var foo = {
	something: function () {
		console.log('Tell me something good')
	}
}
var bar = Object.create(foo)
bar.something()   // 'Tell me something good'

Object.create()会创建一个新对象并把它关联到我们指定的对象,这样我们就可以充分发挥 [[Prototype]] 机制的威力(委托)并且避免不必要的麻烦(比如使用new的构造函数调用会生成 .prototype 和 .constructor 引用)

 

 

你可能感兴趣的:(读书笔记)