Closed sailei1 closed 5 years ago
JavaScript 中的对象有一个特殊的 [[Prototype]] 内置属性,其实就是对于其他对象的引用 Object.create(..) 创建一个对象并把这个对象的 [[Prototype]] 关联到指定的对象。 所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。 所有普通对象都有内置的 Object.prototype,指向原型链的顶端(比如说全局作用域),如果在原型链中找不到指定的属性就会停止。toString()、valueOf() 和其他一些通用的功能都存在于 Object.prototype 对象上,因此语言中所有的对象都可以使用它们。
myObject.foo = "bar”; 设置 如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属 性值。 如果 foo 不是直接存在于 myObject 中,[[Prototype]] 链就会被遍历,类似 [[Get]] 操作。 如果原型链上找不到 foo,foo 就会被直接添加到 myObject 上。 屏蔽 如果属性名 foo 既出现在 myObject 中也出现在 myObject 的 [[Prototype]] 链上层,那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObject.foo 总是会选择原型链中最底层的 foo 属性。
如果 foo 不直接存在于 myObject 中而是存在于原型链上层时 myObject.foo = "bar" 会出现的三种情况
var anotherObject = { a:2 }; var myObject = Object.create( anotherObject ); anotherObject.a; // 2 myObject.a; // 2 anotherObject.hasOwnProperty( "a" ); // true myObject.hasOwnProperty( "a" ); // false myObject.a++; // 隐式屏蔽! anotherObject.a; // 2 myObject.a; // 3 myObject.hasOwnProperty( "a" ); // true
//修改委托属性时一定要小心。如果想让 anotherObject.a 的值增加,唯一的办法是anotherObject.a++。
function Foo() { // ... } var a = new Foo(); Object.getPrototypeOf( a ) === Foo.prototype; // true
在 JavaScript 中,并没有类似的复制类机制。你不能创建一个类的多个实例,只能创建 多个对象,它们 [[Prototype]] 关联的是同一个对象。但是在默认情况下并不会进行复制, 因此这些对象之间并不会完全失去联系,它们是互相关联的。 new Foo() 会生成一个新对象(我们称之为 a),这个新对象的内部链接 [[Prototype]] 关联 的是 Foo.prototype 对象。 最后我们得到了两个对象,它们之间互相关联,就是这样。我们并没有初始化一个类,实 际上我们并没有从“类”中复制任何行为到一个对象中,只是让两个对象互相关联。 **constructor**
function Foo() { // ... } Foo.prototype.constructor === Foo; // true var a = new Foo(); a.constructor === Foo; // true
//a 本身并没有 .constructor 属性。而且,虽然 a.constructor 确实指 向 Foo 函数,但是这个属性并不是表示 a 由 Foo“构造” //.constructor 引用同样被委托给了 Foo.prototype,而Foo.prototype.constructor 默认指向 Foo。 在 JavaScript 中对于“构造函数”最准确的解释是,所有带 new 的函数调用。
function NothingSpecial() {console.log( "Don't mind me!" ); } var a = new NothingSpecial(); // "Don't mind me!” a; // {} new 的副作用
原型继承
function Foo(name) { this.name = name; } Foo.prototype.myName = function() { return this.name; }; function Bar(name,label) { Foo.call( this, name ); this.label = label; } // 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype Bar.prototype = Object.create(Foo.prototype); // 注意!现在没有 Bar.prototype.constructor 了 // 如果你需要这个属性的话可能需要手动修复一下它 Bar.prototype.myLabel = function() { return this.label; }; var a = new Bar( "a", "obj a" ); a.myName(); // "a" a.myLabel(); // "obj a"
polyfill object.create(…)
Object.create = function(o) { function F(){} F.prototype = o; return new F(); };
//Object.create(null) 会 创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]]链接的对象,这个对象无法进行委托。由于这个对象没有原型链,所以instanceof 操作符(之前解释过)无法进行判断,因此总是会返回 false 检查 “类”关系 a instanceof Foo //true Foo.prototype.isPrototypeOf( a ); // true 对象关联 如果在对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的 [[Prototype]],以此类推。这一系列对象的链接被称为“原型链”。 关联关系是备用
var anotherObject = {cool: function() { console.log( "cool!" ); } }; var myObject = Object.create( anotherObject ); myObject.cool(); // "cool!” //由于存在 [[Prototype]] 机制,这段代码可以正常工作。但是如果你这样写只是为了让myObject 在无法处理属性或者方法时可以使用备用的 anotherObject,那么你的软件就会变得有点“神奇”,而且很难理解和维护。 var anotherObject = {cool: function() { console.log( "cool!" ); } }; var myObject = Object.create( anotherObject ); myObject.doCool = function() {this.cool(); // 内部委托! }; myObject.doCool(); // "cool!"
JavaScript 中的对象有一个特殊的 [[Prototype]] 内置属性,其实就是对于其他对象的引用 Object.create(..) 创建一个对象并把这个对象的 [[Prototype]] 关联到指定的对象。 所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。 所有普通对象都有内置的 Object.prototype,指向原型链的顶端(比如说全局作用域),如果在原型链中找不到指定的属性就会停止。toString()、valueOf() 和其他一些通用的功能都存在于 Object.prototype 对象上,因此语言中所有的对象都可以使用它们。
myObject.foo = "bar”; 设置 如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属 性值。 如果 foo 不是直接存在于 myObject 中,[[Prototype]] 链就会被遍历,类似 [[Get]] 操作。 如果原型链上找不到 foo,foo 就会被直接添加到 myObject 上。 屏蔽 如果属性名 foo 既出现在 myObject 中也出现在 myObject 的 [[Prototype]] 链上层,那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObject.foo 总是会选择原型链中最底层的 foo 属性。
如果 foo 不直接存在于 myObject 中而是存在于原型链上层时 myObject.foo = "bar" 会出现的三种情况
//修改委托属性时一定要小心。如果想让 anotherObject.a 的值增加,唯一的办法是anotherObject.a++。
function Foo() { // ... } var a = new Foo(); Object.getPrototypeOf( a ) === Foo.prototype; // true
function Foo() { // ... } Foo.prototype.constructor === Foo; // true var a = new Foo(); a.constructor === Foo; // true
function NothingSpecial() {console.log( "Don't mind me!" ); } var a = new NothingSpecial(); // "Don't mind me!” a; // {} new 的副作用
function Foo(name) { this.name = name; } Foo.prototype.myName = function() { return this.name; }; function Bar(name,label) { Foo.call( this, name ); this.label = label; } // 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype Bar.prototype = Object.create(Foo.prototype); // 注意!现在没有 Bar.prototype.constructor 了 // 如果你需要这个属性的话可能需要手动修复一下它 Bar.prototype.myLabel = function() { return this.label; }; var a = new Bar( "a", "obj a" ); a.myName(); // "a" a.myLabel(); // "obj a"
Object.create = function(o) { function F(){} F.prototype = o; return new F(); };
var anotherObject = {cool: function() { console.log( "cool!" ); } }; var myObject = Object.create( anotherObject ); myObject.cool(); // "cool!” //由于存在 [[Prototype]] 机制,这段代码可以正常工作。但是如果你这样写只是为了让myObject 在无法处理属性或者方法时可以使用备用的 anotherObject,那么你的软件就会变得有点“神奇”,而且很难理解和维护。 var anotherObject = {cool: function() { console.log( "cool!" ); } }; var myObject = Object.create( anotherObject ); myObject.doCool = function() {this.cool(); // 内部委托! }; myObject.doCool(); // "cool!"