2013-03-24 39 views
5

說我有一個類和一些靜態輔助方法是這樣的:分配對象「這個」

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

回答

0

如何只返回新的實例:

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

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 

* 「是」 是指

+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

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對象的屬性(和閉合隱藏變量),你將不會改變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

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/