笔记你不知道的JS原型

2次阅读

共计 1658 个字符,预计需要花费 5 分钟才能阅读完成。

1 [[Prototype]]

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

所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。由于所有的“普通”(内置,不是特定主机的扩展)对象都“源于”(或者说把 [[Prototype]] 链的顶端设置为)这个 Object.prototype 对象,如:toString,valueOf,hasOwnProperty,isPrototypeOf

var anotherObject = {a:2};
// 创建一个关联到 anotherObject 的对象
var myObject = Object.create(anotherObject); 
// myObject = {__proto__: {  a:2, __proto__: Object}};
myObject.a; // 2

属性屏蔽

给一个对象设置属性并不仅仅是添加一个新属性或者修改已有的属性值,如 myObject.foo = “bar”;

如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属性值。

如果 foo 存在于原型链上层,赋值语句 myObject.foo = “bar” 的行为就会有些不同。

如果属性名 foo 既出现在 myObject 中也出现在 myObject 的 [[Prototype]] 链上层,那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为 myObject.foo 总是会选择原型链中最底层的 foo 属性。

如果 foo 不直接存在于 myObject 中而是存在于原型链上层时 myObject.foo = “bar” 会出现的三种情况。

如果在 [[Prototype]] 链上层存在名为 foo 的普通数据访问属性 (参见第 3 章) 并且没有被标记为只读(writable:false),那就会直接在 myObject 中添加一个名为 foo 的新属性,它是屏蔽属性。

如果在 [[Prototype]] 链上层存在 foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在 myObject 上创建屏蔽属性。如果运行在严格模式下,代码会抛出一个错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽。

如果在 [[Prototype]] 链上层存在 foo 并且它是一个 setter(参见第 3 章),那就一定会调用这个 setter。foo 不会被添加到(或者说屏蔽于)myObject,也不会重新定义 foo 这个 setter。

大多数开发者都认为如果向 [[Prototype]] 链上层已经存在的属性 ([[Put]]) 赋值,就一定会触发屏蔽,但是如你所见,三种情况中只有一种 (第一种) 是这样的。如果你希望在第二种和第三种情况下也屏蔽 foo,那就不能使用 = 操作符来赋值,而是使用 Object.defineProperty(..)来向 myObject 添加 foo。

2“类”

构造函数 + 原型函数,两个函数通过 constructor 属性和 prototype 属性相关联。

类关系

function Foo() {}
let foo = new Foo();

1 foo instanceof Foo

instanceof 操作符的左操作数是一个普通的对象,右操作数是一个函数。instanceof 回答的问题是: 在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象

2 Foo.prototype.isPrototypeOf(foo)

isPrototypeOf(..) 回答的问题是: 在 foo 的整条 [[Prototype]] 链中是否出现过 Foo.prototype。我们也可以直接获取一个对象的 [[Prototype]] 链。Object.getPrototypeOf(foo); 如 Object.getPrototypeOf(foo) === Foo.prototype; // true 或者 a.__proto__ === Foo.prototype; // true

正文完
 0