0

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

我有以下声明:

// 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 };
};

ThensomeOtherMember不再是静态的,而是 Array 的第一个实例拥有它自己的。我不明白这种行为,因为毕竟我在这两种情况下都someOtherMember通过访问this,所以我无法弄清楚为什么它在第一种情况下是静态的,而在第二种情况下它不是静态的。

4

4 回答 4

3

JS 中没有静态属性之类的东西。您看到的是原型继承的正常行为。关键概念是这样的:数组,实际上所有对象,都是稀疏的 一个实例没有属性,除非它被显式分配给该实例。只要不发生这种情况,原型就拥有所有属性:

第一种情况
你为什么看到I changed, My value is not static, My value is not static?很简单:当数组被实例化时,所有的实例看起来都会有一个名为 的属性someMember,但实际上并没有。当您尝试访问时,anArray.someMemberJS 将首先扫描该属性的实例,如果该实例没有定义该属性,则 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新的Object 文字重新分配给属性的方法时,您实际上是在创建与案例一相同的情况:直接将新对象分配给属性,这导致 JS扫描原型,而只是在实例级别分配属性。你可以使用Object.getPrototypeOf(this)or (对于旧版浏览器)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});

可以在 MDN 上找到更多示例

于 2012-10-12T09:13:29.380 回答
0

在 someOtherMember 中,一个 Object 实例在 Array 的所有实例之间共享。

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

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

于 2012-10-12T09:09:21.670 回答
0

第一种情况很好理解。

第二种情况(someOtherMember不是静态成员),您someOtherMember每次调用时都会覆盖changeMember(删除静态成员value)因此不再存在静态成员。

于 2012-10-12T09:09:47.300 回答
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 };
};
于 2012-10-12T09:22:05.630 回答