2017-01-29 44 views
2

海蘭我寫的JS和HTML一個快速和骯髒的列表的用戶界面,可以過濾: https://jsfiddle.net/maxbit89/2jab4fa4/找到了JavaScript Setter錯誤?

所以這種用法是這樣的(小提琴行:96):

var list = new ui_list(document.body, 200, 300, "Test"); 
var encoder = function(dom, value) { 
    console.log("begin encoding"); 
    console.log(value) 
    dom.innerHTML = value.n; 
} 

list.add({'n': 1}, function() { 
    this.value.n++; 
    console.log(this.value.n); 
// this.value = this.value; 
}, encoder); 

那麼什麼這basicaly確實是創建列表,並增加了一個元素它具有一個對象:{「n」個:1}作爲值和onClickHandler(上list.add第二參數)至極應由1(小提琴線增加值: 104)

但它不會做到這一點,直到您取消註釋在撥弄線106。 (使用FireFox 50.1.0和Edge瀏覽器進行測試)

有沒有任何機構知道爲什麼js的行爲如此呢? 在一個多simplier例如,這工作得很好:

var myObj= { 
    'onvalueChange' : function() { 
     console.log('value changed'); 
    }, 
    'print' : function() { 
      console.log('value:'); 
     console.log(this.value); 
     console.log(this.value.n); 
    } 
}; 

Object.defineProperty(myObj, "value", { 
    get: function() { return this._value; }, 
    set: function(value) { 
     this.onvalueChange(); 
     this._value = value; 
    } 
}); 

myObj.value = {'n' : 1}; 

myObj.value.n++; 

myObj.print(); 
+0

你只能「看」屬性一層深;更改爲子屬性不使用的setter /吸氣 – dandavis

回答

3

首先,你必須這樣定義的setter:

set: function (value) { 
    this.encoder(this, value); 
    this._value = value; 
} 

這意味着每次值設置,編碼器將被調用用新值更新等效的DOM元素。

但隨後事件監聽器函數內你有:

function() { 
    this.value.n++; 
    console.log(this.value.n); 
    //this.value = this.value; 
} 

,你認爲this.value.n++被設定值(意味着它調用這意味着編碼器將被調用,以更新的DOM元素的setter)。但事實並非如此。 this.value.n++實際上是調用的getter。爲了解釋這更多:

this.value.n++; 

是一樣的:

var t = this.value; // call the getter 
t.n++; // neither call the getter nor the setter. It just uses the reference (to the object) returned by the getter to set n 

所以,當你取消對該行this.value = this.value;,二傳手被調用,而編碼器被調用來更新DOM元素。

因此,要解決你的問題之一:

  • 讓getter中調用編碼器像你一樣的二傳手(但這種方法是非常哈克,因爲它會更新DOM元素即使沒有設置任何設置,每次獲得呼叫)。
  • 更改這個this.value.n++;實際上調用setter,如:this.value = {n: this.value.n + 1};(但這也是hacky,如果值有很多鍵 - 值對,那麼你必須在這裏設置它們,以設置n)。
  • 調用事件監聽器內部的編碼器,這將是最好的方法(或者如果你不想傳遞參數給另一個函數(例如this.callEncoder()),它會調用它並[你]調用這個新的函數代替了事件監聽器)。
+0

紮實的分析和一個很好的答案。 – Amy

+0

好吧,這是一個奇怪的行爲:如果有人遇到同樣的問題,這裏是一個小例子:https:// jsfiddle。net/maxbit89/ehf3mzhn/ – maxbit89

+0

*奇怪的行爲我的意思是它可能是無用的,因爲你不能真正在框架中使用這個,當一個「最終用戶」不知道如果有一個getter/setter涉及,他遇到了這個問題?。 – maxbit89