JavaScript getter 和 setter 在 dojo 上定义 class 没有按预期工作

JavaScript getter and setter on dojo defined class do not work as expected

我在dojo中定义了一个"class",一个属性 foo定义了 JavaScript gettersetter.

在下面的代码中,setter 从未被调用,getter 被调用了两次。

我想知道:

我知道 dojo 自定义 getter 和 setter,但我想了解为什么在 "class" 中不起作用。

现场演示: https://jsfiddle.net/yz8ft4eh/

require(["dojo/_base/declare"], function(declare) {
  var Person = declare(null, {
    _foo: null,
    get foo() {
      console.log('getter foo ' + this._foo);
      return this._foo;
    },
    set foo(value) {
      console.log('setter foo ' + value);
      this._foo = value;
    },
    constructor: function(name) {
      this.name = name;
      this.foo = 1000;
    }
  });
  var folk = new Person("phiggins");
  folk.foo = 2000;
});

问题是 Dojo 不明白你在那里有一个 getter/setter 属性。重要的是要记住 lot 的 Dojo 是很久以前写的,甚至在 2009 年的 ES5 规范发布之前。虽然该项目处于活动状态,但一天中只有这么多时间,他们可能没有时间回去为各地更新的事物改进支持。 (也就是说,令我惊讶的是,在 getter/setter 属性被添加到 JavaScript 七年后,这在 2016 年仍然是一个问题。)

我无法在网上找到 v1.10.4 的未压缩源代码(您 fiddle 中的那个),但我可以找到 1.10.6,它使用了一个简单的 for-in 循环复制您的属性。我们可以看到 declare 调用了 safeMixin,它是这样做的:

for (name in source) {
    t = source[name];
    if ((t !== op[name] || !(name in op)) && name != cname) {
        if (opts.call(t) == "[object Function]") {
            // non-trivial function method => attach its name
            t.nom = name;
        }
        target[name] = t;
    }
}

要支持使用 getter/setter 属性,必须在此处使用 Object.getOwnPropertyDescriptor 或类似属性。因此,它没有正确复制 属性,而是读取它的值。

您可以通过在 constructor 中初始化 属性 来解决这个问题:

require(["dojo/_base/declare"], function(declare) {
  function getFoo() {
    console.log('getter foo ' + this._foo);
    return this._foo;
  }
  function setFoo(value) {
    console.log('setter foo ' + value);
    this._foo = value;
  }
  var Person = declare(null, {
    _foo: null,
    constructor: function(name) {
      Object.defineProperty(this, "foo", {
        get: getFoo,
        set: setFoo
      });
      this.name = name;
      this.foo = 1000;
    }
  });
  var folk = new Person("phiggins");
  folk.foo = 2000;
});
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.10.0/dijit/themes/claro/claro.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>