ES6:如何为对象及其属性设置getter / setter

时间:2017-04-07 17:30:16

标签: javascript ecmascript-6

使用JS getter和setter,我的目标是创建以下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()舍入为整数。

3 个答案:

答案 0 :(得分:3)

如果你必须使用getter和setter,一个相对简单的解决方案是将var myArray = ["iPhone", "Android"] // mutable let myArray = ["iPhone", "Android"] // immutable x定义为getter和setter。

y

但您必须注意,每次{em>读取访问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

答案 1 :(得分:1)

  

......对此的用例可能是thing.xthing.y应始终使用Math.round()舍入为整数。

考虑使用Proxy



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




代理允许您捕获属性上的get或set操作。

警告: IE目前暂时不支持代理。如果我有Google's Proxy polyfill的CDN,我会将其添加到代码段,但我不知道。此外,如果您使用Babel,那么babel-plugin-proxy

答案 2 :(得分:0)

我认为你不应该使用这种模式,我认为你很难让它发挥作用。请考虑以下情况:

// 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;

由于我们返回了一个带有位置getter的简单地图,因此position.x只是分配给返回的副本,并没有修改foo的实际位置。解决这个问题的一种方法是让位置getter返回一个更聪明的对象,该对象具有对foo实例和正确的getter / setter的引用。这样就可以了:

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

bar.position getter将返回一个仅作为bar x / y属性视图的对象。然后,foo.position setter会将bar的x / y属性复制到其私有存储中。说得通。 bar.x += 10广告仅限于bar的位置。

但是,以下情况会非常混乱:

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

这会产生一种错觉,即temp是foo.position的备份副本,但它不是。{1}}。这是一个观点。一旦foo的位置发生变化,我们就会丢失数据。复制这个职位并不容易。

您可以尝试让您的position对象实际存储数据的副本以及对原始数据的引用,这样您就可以同时设置和获取...这是一个无穷无尽的问题

但是在这一点上,你的糖语法使得维护所有内容变得更加困难并且效率低得多。

因此,我实际上并没有做到这一点,以至于x和y getter / setter都在foo / bar对象本身上。我还要在foo / bar对象中创建任何代码,将它们视为不可变的。