发现JavaScript Setter错误?

时间:2017-01-29 20:55:40

标签: javascript

Hy我用js和html编写了一个快速而又脏的列表ui,可以过滤: https://jsfiddle.net/maxbit89/2jab4fa4/

所以这个的使用看起来像这样(小提琴行: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);

所以这个基本的做法是创建一个List并为其添加一个Element,它有一个Object:{' n':1}作为值和onClickHandler(list.add上的第二个参数)应该将值增加1(小提琴线:104)

但它不会这样做,直到你取消小提琴中的106行。 (使用FireFox 50.1.0和Edge Browser进行测试)

有没有人知道为什么js会像这样? 在一个更简单的例子中,这很好用:

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();

1 个答案:

答案 0 :(得分: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++正在设置值(意味着它调用setter,这意味着将调用编码器来更新DOM元素)。但事实并非如此。 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;时,将调用setter,并调用编码器来更新DOM元素。

所以要解决你必须要解决的问题:

  • 像对setter一样在getter中调用编码器(但是这个解决方案非常hacky,因为它会在每次getter调用时更新DOM元素,即使没有设置任何东西)。
  • 更改此this.value.n++;以实际调用setter,如:this.value = {n: this.value.n + 1};(但这也很hacky,因为值有很多键值对,那么你必须将它们全部放在这里才能设置n)。
  • 在事件监听器内调用编码器,这是最好的方法(或者如果你不想将参数传递给它,那么会调用另一个函数(例如this.callEncoder())它和[你]在事件监听器内调用新函数。)。