繁体   English   中英

ES6:如何对对象及其属性进行吸气/设置

[英]ES6: How to have a getter/setter for an object AND its properties

我旨在使用JS getter和setters创建以下API案例:

// the user should be able to write this to update thing

thing = {
   x: 1,
   y: 2
}

// OR they should be able to write this

thing.x = 1
thing.y = 2

现在我正在使用这样的代码:

 get thing() {
   return {
     x: this._thing.x,
     y: this._thing.y
   };
 }

 set thing(value) {
   this._thing.x = value.x,
   this._thing.y = value.y
 }

这支持第一种情况,但不支持第二种情况。

可以用任何合理的简单方法来完成吗?

编辑:我将键入一个示例,但为此的用例可能是thing.xthing.y应该始终使用Math.round()舍入为整数。

如果必须使用getter和setter,则相对简单的解决方案是将xy也定义为getter和setter。

get thing() {
  var self = this;
  return {
    get x() {
      return self._thing.x;
    }
    set x(value) {
      self._thing.x = value;
    }
    // same for y
  };
}

但是您必须意识到,每次访问thing进行读取时 ,都会创建一个新对象。 尽管您可以通过缓存该对象并重用它来避免这种情况。

实际上,我可能_thing 我只存储_x_y并按需生成一个对象:

class Foo {
  get thing() {
    if (this._thing) {
      return this._thing;
    }

    var self = this;
    return this._thing = {
      get x() {
        return self._x;
      }

      set x(value) {
        self._x = value;
      }
    };
  }

  set thing(value) {
    this._x = value.x;
    this._y = value.y;
  }
}

...一个用例可能是thing.xthing.y应该始终使用Math.round()舍入为整数。

考虑使用代理

 class Parent { constructor() { this.thing = {x: 15.6, y: 2.1}; } set thing(value) { this._thing = new Proxy(value, { get: function(target, property, receiver) { // Catch all get access to properties on the object if (['x', 'y'].includes(property)) { // for x and y, return the real value, rounded return Math.round(target[property]); } } }); } get thing() { return this._thing; } } var parent = new Parent(); console.log(parent.thing.x); // 16 parent.thing.x = 13.2; console.log(parent.thing.x); // 13 parent.thing = {x: 10.1, y: 5.4}; console.log(parent.thing.y); // 5 // This works for the Jacque Goupil's conundrum var anotherRef = parent.thing; anotherRef.x = 5.8; console.log(parent.thing.x); // 6 // In fact, if you wanted to dance with the devil... var plainObj = {x: 10.1, y: 5.4}; parent.thing = plainObj; plainObj.x = 7.2; console.log(parent.thing.x); // 7 parent.thing.x = 22.2; console.log(plainObj.x); // 22.2 

代理允许您捕获属性的获取或设置操作。

警告: IE目前暂时不支持代理。 如果我有一个用于Google Proxy polyfill的CDN,我会将其添加到摘要中,但我没有。 另外,如果您使用Babel ,则还有babel-plugin-proxy

我认为您不应该使用这种模式,并且我认为您将无法使其正常工作。 考虑以下情况:

// calls the position setter on foo
foo.position = {x: 10, y: 20};

// calls the position getter on foo, obtaining a simple {x:10,y:20} object
var pos = foo.position;

// calls the position getter on foo and then the x getter on position
var xx = foo.position.x;

到目前为止,一切都有意义。 然后我们进入这种情况:

// calls the position getter on foo and then the x setter on position
foo.position.x = 7;

由于我们返回了一个带有位置获取器的简单地图,所以position.x只是分配给返回的副本,而不会修改foo的实际位置。 解决此问题的一种方法是让位置获取器返回一个更智能的对象,该对象具有对foo实例和适当的获取器/设置器的引用。 这将允许执行以下操作:

foo.position = bar.position;
bar.x += 10;

所述bar.position吸气剂都将返回一个仅作为一个视图中的对象bar “SX / y属性。 然后, foo.position设置程序会将bar的sx / y属性复制到其专用存储中。 说得通。 bar.x += 10广告仅针对bar的位置。

但是,以下情况将非常令人困惑:

var temp = foo.position;
foo.position = bar.position;
bar.position = temp;

这产生了一种幻觉,认为temp是foo.position的备份副本,但事实并非如此。 这是一个观点。 一旦foo的位置发生变化,我们就会永远丢失数据。 没有简单的方法可以复制该职位。

您可以尝试使position对象实际存储数据的副本以及原始数据的引用,以便既可以设置又可以获取...这是一个无休止的问题。

但是在这一点上,您的糖语法使所有内容的维护变得更加困难,效率也大大降低。

因此,实际上我没有做所有这些事情,而是使x和y getter / setters位于foo / bar对象本身上。 我还要使foo / bar对象内的任何代码都将位置视为不变。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM