原型为数组的Javascript对象成员将被所有类实例共享
有没有人注意过这种行为? 这真的把我扔了…我会希望原型数组是专用于每个类实例,而不是在所有类实例之间共享。
有人可以验证这是正确的行为,也许更详细地解释这种行为?
注意注释代码以及它如何影响脚本的行为。
<html> <head> <script type="text/javascript"> function print_r( title, object ) { var output = ''; for( var key in object ) { output += key + ": " + object[ key ] + "\n"; } output = title + "\n\n" + output; alert( output ); } function Sandwich() { // Uncomment this to fix the problem //this.ingredients = []; } Sandwich.prototype = { "ingredients" : [], "addIngredients" : function( ingArray ) { for( var key in ingArray ) { this.addIngredient( ingArray[ key ] ); } }, "addIngredient" : function( thing ) { this.ingredients.push( thing ); } } var cheeseburger = new Sandwich(); cheeseburger.addIngredients( [ "burger", "cheese" ] ); var blt = new Sandwich(); blt.addIngredients( [ "bacon", "lettuce", "tomato" ] ); var spicy_chicken_sandwich = new Sandwich(); spicy_chicken_sandwich.addIngredients( [ "spicy chicken pattie", "lettuce", "tomato", "honey dijon mayo", "love" ] ); var onLoad = function() { print_r( "Cheeseburger contains:", cheeseburger.ingredients ); }; </script> </head> <body onload="onLoad();"> </body> </html>
非常感谢。
对象的原型只是一个对象。 原型属性在从该对象继承的所有对象之间共享。 如果创建一个“类”的新实例(JS中不存在类),也就是从原型继承的对象,则不会创建属性的副本。
这只会影响你如何使用这些继承的属性:
function Foo() {} Foo.prototype = { array: [], func: function() {} } a = new Foo(); b = new Foo(); a.array.push('bar'); console.log(b.array); // prints ["bar"] b.func.bar = 'baz'; console.log(a.func.bar); // prints baz
在所有这些情况下,你总是使用同一个对象。
但是,如果您为对象的属性赋值 ,则该属性将在对象本身而不是原型上设置/创建,因此不会共享:
console.log(a.hasOwnProperty('array')); // prints false console.log(a.array); // prints ["bar"] a.array = ['foo']; console.log(a.hasOwnProperty('array')); // prints true console.log(a.array); // prints ["foo"] console.log(b.array); // prints ["bar"]
如果你想为每个实例创建自己的数组,你必须在构造函数中定义它:
function Foo() { this.array = []; }
因为在这里, this
是指当您调用new Foo()
时生成的new
对象。
经验法则是: 实例 – 特定的数据应该分配给构造函数中的实例 , 共享数据(如方法)应该分配给原型 。
您可能需要阅读描述基于类的原型语言与基于原型的语言之间差异以及对象如何工作的对象模型的细节 。
更新:
您可以通过Object.getPrototypeOf(obj)
访问对象的原型(可能不适用于非常旧的浏览器),并且Object.getPrototypeOf(a) === Object.getPrototypeOf(b)
为您提供了true
。 这是同一个对象,也被称为Foo.prototype
。
行为是正确的。 在运行时将[]
为new Array()
,但只创建一个这样的数组。
换句话说, Obj.prototype = {...}
就像任何其他Obj.prototype = {...}
一样执行。
当你做var exp1 = new C()
,JavaScript设置exp1.[[Prototype]] = C.prototype
。 当你访问实例的属性时,JavaScript首先检查它们是否直接存在于该对象上,如果不存在,它将在[[Prototype]]
查找[[Prototype]]
。 这意味着您在原型中定义的所有东西都可以被所有实例共享,甚至可以稍后更改原型的一部分,并在所有现有实例中显示更改。