将对象分配给“this”

时间:2013-03-24 12:38:54

标签: javascript

假设我有一个类和一些静态辅助方法,如下所示:

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

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

4 个答案:

答案 0 :(得分:1)

  

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对象(以及闭包隐藏变量)的属性,您不会更改instance,而revealVar()将保持2。

  

有一种简单的方法吗?

是的,可以通过编程方式完成。最简单的方法是call构造函数(再次) on 当前实例,就像使用new keyword调用时一样:

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

然而,你不能像创建一个全新实例的静态函数那样使用它。您可以将其置于静态方法中,并使用replaceMethis调用该方法,或者直接将其放在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

答案 1 :(得分:0)

如何返回新实例:

function MyClass(myVar) {
    // ...

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

    // ...
}

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

答案 2 :(得分:0)

有两个原因导致这种情况无法在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

*“是”意味着“在各方面完全相同”

答案 3 :(得分:0)

我想做一些非常相似的事情。遗憾的是,无法为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/