我一直在使用它作为一个非常好的解决方法,如何为我的对象声明静态成员但我真的不明白为什么它们变成静态所以我需要有人向我解释以下行为。
我有以下声明:
// 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
不再是静态的,而是Array的第一个实例获得它自己的。我不理解这种行为,因为毕竟我在两种情况下都通过someOtherMember
访问this
,所以我无法弄清楚为什么它在第一种情况下是静态的而在第二种情况下它不是静态的。
答案 0 :(得分:3)
JS中没有静态属性。你所看到的是原型继承的正常行为。关键概念是: Arrays,实际上所有对象都是稀疏的实例没有属性,除非它被明确地分配给该实例。只要不发生这种情况,原型就会拥有所有属性:
第一个案例
你为什么看到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
引用。对象文字的 Reference 不会改变,只会改变对象本身。就像在任何其他语言中一样:处理引用时,对象可以根据需要进行更改,引用将保持不变(其值可能会更改,但其内存地址不会更改)。
当您重新定义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});
的更多示例
答案 1 :(得分:0)
在someOtherMember中,在Array的所有实例之间共享一个Object实例。
在第一种情况下,您要更改该对象的值,因此所有Array实例的值都会更改。
在第二种情况下,您正在更改对象本身。因此,Array的实例将包含其他对象。
答案 2 :(得分:0)
第一个案例很清楚。
第二种情况(其中someOtherMember
不是静态成员),每次调用someOtherMember
(删除静态成员changeMember
时)都会覆盖value
不再存在静态成员。
答案 3 :(得分: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 };
};