2012-10-12 141 views
0

我一直在使用这一段时间作为一个非常好的解决方法,如何为我的对象声明静态成员,但我真的不明白他们为什么变成静态的,所以我需要有人向我解释以下行为。静态javascript成员

我有以下声明:

// Primitive so nothing interesting here 
Array.prototype.someMember = "My value is not static"; 
// Object containing a primitive, now this is the deal 
Array.prototype.someOtherMember = { 
    value: "My value is static" 
}; 

Array.prototype.changeMember = function (newValue) { 
    // Change the primitive value 
    this.someMember = newValue; 
    // Change the primitive value inside the object 
    this.someOtherMember.value = newValue; 
}; 

,如果这是测试了以下方式:

var arr1 = [], arr2 = [], arr3 = []; 
arr1.changeMember('I changed'); 
alert(arr1.someMember + ', ' + arr2.someMember + ', ' + arr3.someMember); 
alert(arr1.someOtherMember.value + ', ' + arr2.someOtherMember.value + ', ' + arr3.someOtherMember.value); 

结果是:

我变了,我的价值不静态,我的价值不是一成不变的

我变,我变,我变

现在,如果我重新分配在changeMember方法这样整个对象:

Array.prototype.changeMember = function (newValue) { 
    // Change the primitive value 
    this.someMember = newValue; 
    // Change the object 
    this.someOtherMember = { value: newValue }; 
}; 

然后someOtherMember不再是静态的,而是数组的第一个实例得到它自己的。我不理解的行为,因为毕竟我是通过在这两种情况下this访问someOtherMember,所以我想不通为什么它在第一种情况下静态的,它不是在第二个静态的。

回答

2

JS中没有这样的静态属性。你所看到的是原型遗传的正常行为。关键概念是这样的:阵列,以及所有的对象,是稀疏实例不会有一个属性,除非它明确地分配到该实例。只要不发生,原型持有的所有属性:

第一种情况
为什么你看到I changed, My value is not static, My value is not static?简单:当数组被实例化时,所有实例出现有一个名为someMember的属性,但实际上它们不是。当您尝试访问anArray.someMember JS会先扫描实例该属性,如果实例没有属性定义,JS将转向原型,寻找someMember那里。在您的代码段changeMember方法使用this,指代调用该方法,而不是Object.getPrototypeOf(this).someMember实例。后者是在原型级别上更改属性的方式。总之:

arr1.changeMember('I changed'); 
// is the same as doing: 
arr1.someMember = 'I changed'; 
arr1.someOtherMember.value = 'I changed'; 

分配到someMember是一个简单的任务,设置一个实例的属性。

第二种情况
第二分配重新分配的对象的属性,即通过引用Array.prototype.someOtherMember参考来的对象字面不改变,只有对象本身。就像使用其他语言一样:在处理引用时,对象可以随意更改,引用将保持不变(它的值可能会更改,但其内存地址不会)。
当您重新定义changeMember方法将新的对象文字重新分配给某个属性时,实质上就是创建了与情况1相同的情况:直接将新对象分配给属性,导致JS 而不是扫描原型,但仅在实例级别分配属性。您可以使用Object.getPrototypeOf(this)(旧版本浏览器)this.prototype

Array.prototype.changeMember = function (val) 
{ 
    this.someMember = 'I changed At instance level'; 
    Object.getPrototypeOf(this).someMember = 'Reassing prototype property to '+ val; 
    Object.getPrototypeOf(this).someOtherMember = {value:val};//changes proto only 
}; 

说了这么多,如果你想要的东西就像一个静态属性,你使用Object.defineProperty的更好:

Object.defineProperty(Array.prototype,'sortofStatic',{value:'I cannot be changed',writable:false,configurable:false}); 

更多示例can be found on MDN

+0

那么Object.defineProperty和Array.prototype.someOtherMember = { value:“我的值是静态的” }之间的区别是什么? –

+0

@ KonstantinD-Infragistics:使用'Object.defineProperty',你不分配一个对象字面值,你将一个属性定义为只读/ rw,(非)enumerable,...只是阅读文档 –

0

在某些其他成员中,Object的一个实例在Array的所有实例之间共享。

在第一种情况下,您正在更改该对象的值,因此该值将更改为Array的所有实例。

在第二种情况下,您正在更改对象本身。所以一个数组的实例将包含另一个对象。

+0

不完全正确:没有数组具有'someMember'属性, JS直接从原型获得该值。然而,当在数组实例上调用'changeMember'函数时,该实例是_augmented_并获得它自己的'someMember'属性,其他数组实例仍然没有额外的属性。 someMember的值也不是一个对象,它是一个常量 –

0

第一种情况是众所周知的。

第二种情况(其中someOtherMember不是静态成员),你overwritting每次调用changeMember时间someOtherMember(删除静态成员value)因此不再存在的静态成员。

0
Array.prototype.someMember = "My value is not static"; 

// Here `someOtherMember` is simply a property which points to a memory location 
// So initially it will point to the same memory location for all instances of `Array` 
Array.prototype.someOtherMember = { 
    value: "My value is static" 
}; 

Array.prototype.changeMember = function (newValue) { 

    this.someMember = newValue; 

    // Here we change a value stored in the memory location pointed by `someOtherMember` 
    // As all instances point to the same memory location this change will reflect in all instances 
    this.someOtherMember.value = newValue; 
}; 


Array.prototype.changeMember = function (newValue) { 

    this.someMember = newValue; 

    // Here for this particular instance we make `someOtherMember` point to a new memory location. 
    // All instances will point to the old memory location until `changeMember` is invoked. 
    this.someOtherMember = { value: newValue }; 
};