使用 defineProperty set 函数实际设置 属性 值是不可能的吗?

Is this imposibble that using defineProperty set function to actually set the property value?

我想使用 vanilla JavaScript.

实现双向数据绑定(如 Angular 或 Vue)

模型部分的视图我可以使用添加输入事件监听器, 和要查看部分的模型,我想使用 Object.defineProperty 的设置功能。

在 defineProperty 的 set 函数中,我需要更改视图的值并设置 属性 值,但这会导致 "Maximum call stack size exceeded", 因为 set property value 会一次又一次地递归 运行。

现在的问题是:有没有办法既可以使用 set 函数又可以同时设置它的 属性 值?

现在我的代码:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>2 Way Data Binding</title>
</head>
<body>
  text: <input id="text" class="text" type="text">
</body>

<script type="text/javascript">

  var input = document.querySelector("#text");
  var data = {};
  Object.defineProperty(data, "text", {

    get: function(){
        return input.value
    },
    set: function(newValue){

      input.value = newValue;
      // data.text = newValue;  // <------ this is the problem
    }
  })

  input.input = function(){
    data.text = data.text;
  }

</script>
</html>

回答你的问题——不。如果你有一个setter,你不能在没有循环的情况下转身设置值。另一种方法是在只有 get()set() 方法与之交互的对象上有一个私有的 属性。外界只会使用具有 getters/setters.

的属性

不确定这是否是实现绑定的好方法,但这是一种使用 setter 来设置 属性:

的方法

const data = {
  // _text is the source of truth
  _text: "some text",
  get text() {
    return this._text
  },
  set text(newValue) {
    input.value = newValue;
    this._text = newValue;
  }
};

const input = {
  value: data.text
}

// original value
console.log(data.text)
console.log(input.value)

// change it
data.text = "other text"
console.log(data.text)
console.log(input.value)

In the setter function I need to set the property value, but it will cause "Maximum call stack size exceeded", because the set property value will recursively run again and again.

是的。不要那样做。设置 input.value 就足够了,getter 已经报告了新值。

when I console.log my view model (in my code above is data), the result is {} (a empty object). So say, if i want to iterate my view model, that can't be done.

嗯,这是一个非常不同的问题。这可以通过 属性 enumerable:

轻松解决
var input = document.querySelector("#text");
var data = {};
Object.defineProperty(data, "text", {
    enumerable: true,
    get: function(){
        return input.value
    },
    set: function(newValue){
        input.value = newValue;
    }
});
console.log(data);