6

假设我有一个类和一些像这样的静态辅助方法:

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

4 回答 4

2

instance.replaceMe( 40 ).revealVar();警报 42

好的,这样return MyClass.staticHelper(this, value);就足够了。问题只是下一次调用instance.revealVar()现在应该警告 2 还是 42 - 如果您想instance更改为 42,它会变得更加复杂:

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

…因为this不是一个公共变量,而是一个关键字,并计算出当前执行上下文的 ThisBinding 的值,该值取决于函数的输入方式- 你不能分配给它,你只能在调用函数时设置它.

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

不幸的是,您必须这样做,而不更改instance对象的属性(以及闭包隐藏变量),您不会更改instance并且revealVar()将保持 2。

有没有一种简单的方法可以做到这一点?

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

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

然而你不能像创建一个全新实例的静态函数那样使用它。replaceMe要么你把它放在一个静态方法中并从with中调用它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;
};

这意味着覆盖旧的属性,并且旧的闭包现在可以被垃圾收集,因为没有任何东西可以引用它们。

顺便说一句,我建议将您的方法放在原型上,而不是在构造函数中分配它们

于 2013-03-24T14:24:57.620 回答
0

只返回新实例怎么样:

function MyClass(myVar) {
    // ...

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

    // ...
}

MyClass.staticHelper = function (instance, value) {
    return new MyClass( instance.myVar += value );
}
于 2013-03-24T12:43:36.960 回答
0

这在 Javascript 中不起作用有两个原因。

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

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

其次,即使this=z可能,该方法无论如何都会失败,因为 Javascript 按值传递,因此不可能有一个函数来更改其参数的值:

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

*“是”的意思是“在各方面都完全一样”

于 2013-03-24T12:50:14.137 回答
0

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

请注意,这只会更新对实例的单个引用。你可以在这里阅读更多内容:有更好的方法来模拟 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/

于 2013-03-24T14:37:34.983 回答