分配对象“这个”

问题描述:

说我有一个类和一些静态辅助方法是这样的:分配对象“这个”

function MyClass (myVar) { 
    this.myVar = myVar; 

    this.replaceMe = function (value) { 
     // this will fail 
     this = MyClass.staticHelper(value); 

     return this; 
    } 

    this.revealVar = function() { 
     alert(this.myVar); 
    } 
} 

MyClass.staticHelper = function (instance, value) { 
    return new MyClass(instance.myVar + value); 
} 

我想要做的是这样的:

var instance = new MyClass(2); 

instance.revealVar(); // alerts 2 
instance.replaceMe(40).revealVar(); // alerts 42 

的原因是,我的类有一个稍微复杂的结构,我不想每次手动分配所有内部变量,而是替换整个对象。有没有简单的方法来做到这一点?

+2

看起来你只是想'返回MyClass.staticHelper(this,value);'。你不能替换'this',但你可以返回一个新的类似的对象。 – 2013-03-24 12:41:10

+0

这只会返回调用链中的新对象,但不会实际替换该实例。 – 2013-03-24 12:41:57

+0

是的,那是不可能的。你可以为整个类创建一个包装器,并保留对实际实例的内部引用。 – 2013-03-24 12:42:47

如何只返回新的实例:

function MyClass(myVar) { 
    // ... 

    this.replaceMe = function (value) { 
     return MyClass.staticHelper(this, value); 
    } 

    // ... 
} 

MyClass.staticHelper = function (instance, value) { 
    return new MyClass(instance.myVar += value); 
} 
+0

正如问题的评论所述,这实际上不会取代实例,即在调用链之外,对象将不会被触及。 – 2013-03-24 12:45:10

+0

@IngoBürk我还添加了'+ ='而不是'=',以便改变对象属性。 – 0x499602D2 2013-03-24 12:45:38

+0

哦,我没有看到。但是这打破了我的问题的目的:我的课程需要在变化时对几个变量进行更新。我正在寻找一种不必手动执行此操作的方法。 – 2013-03-24 12:46:24

有两个原因,这是不打算在Javascript工作。

首先,尽管它看起来像一个变量,但this实际上是一个函数调用*,因此不能分配给它。 this=foobar()=baz相同。因此,它是不可能有这样的代码:

a = 5 
a.change(10) 
alert(a == 10) // nope 

其次,即使this=z是可能的,这种做法会失败反正,JavaScript,因此经过价值,因此它不可能有改变的值的函数它的参数:

a = 5 
change(a) 
alert(a == 10) // nope 

* “是” 是指

+0

你如何看待'this'会是一个函数调用? – Bergi 2013-03-24 12:51:41

+3

该规范没有说它是一个函数调用。 [只提到'ThisBinding'](http://es5.github.com/#x10.4.3),它被描述为*“在与这个执行上下文相关的ECMAScript代码内与'this'关联的值。”* (http://es5.github.com/#x10.3,http://es5.github.com/#x11.1.1)。 – 2013-03-24 12:56:53

+0

函数内的'this'指针是只读值,不是函数调用。这就是'this'的分配不起作用的原因。 – 2013-03-24 14:17:59

instance.replaceMe(40).revealVar();警报 “在各方面完全一致” 42

好的,对于return MyClass.staticHelper(this, value);就足够了。现在的问题是instance.revealVar()下一个电话只有是否现在应该提醒2或42 - 如果你想instance被改为42它变得更加复杂:

this = MyClass.staticHelper(value); // this will fail 

...因为this不是普通的变量,而是一个关键字evaluates to the value of the ThisBinding of the current execution context其中is set depending on how the function is entered - 你不能分配给它,你只能在调用该函数时进行设置。

我不想每次手动分配所有内部变量,而是替换整个对象。

不幸的是,你必须这样做,在不改变instance对象的属性(和闭合隐藏变量),你将不会改变instancerevealVar()将保持2

是否有一个简单的方法来做到这一点?

是的,它可以以编程方式完成。最简单的方法是call构造上(再次)当前实例一样,当与调用它发生的new keyword

MyClass.call(instance, instance.myVar + value); 

然而,你不能用这个像它创建了一个完全静态函数新实例。要么你把它放在一个静态方法中,并从replaceMe调用this,或者你直接把它放在replaceMe

如果需要,起初返回一个全新的实例的静态方法,你可以使用,以及通过对旧实例复制新的属性:

….replaceMe = function(val) { 
    var newInst = MyClass.staticHelper(this, val); // new MyClass(this.myVar+val); 
    for (var prop in newInst) 
     if (newInst.hasOwnProperty(prop)) 
      this[prop] = newInst[prop]; 
    return this; 
}; 

这意味着覆盖旧的属性,旧的关闭现在可以被垃圾收集,因为没有任何东西指向他们了。我想推荐到put your methods on the prototype instead of assigning them in the constructor

我想做一些非常相似的事情。不幸的是,没有办法为this赋值 - this指针是一个只读变量。然而,下一个最好的事情是使用getter和setter对象来更改包含实例本身的变量。

请注意,这只会更新对实例的单个引用。你可以阅读更多关于它在这里:Is there a better way to simulate pointers in JavaScript?

因此,这是它如何工作的:

function MyClass(pointer, myVar) { 
    this.myVar = myVar; 

    this.replaceMe = function (value) { 
     pointer.value = MyClass.staticHelper(this, pointer, value); 
     return pointer.value; 
    }; 

    this.revealVar = function() { 
     alert(this.myVar); 
    }; 
} 

MyClass.staticHelper = function (instance, pointer, value) { 
    return new MyClass(pointer, instance.myVar + value); 
}; 

这是如何创建pointer并使用它:

var instance = new MyClass({ 
    get value() { return instance; }, 
    set value(newValue) { instance = newValue; } 
}, 2); 

instance.revealVar();    // alerts 2 
instance.replaceMe(40).revealVar(); // alerts 42 

这不是最优雅解决方案,但它完成了工作。你可以看到这个代码在行动:http://jsfiddle.net/fpxXL/1/