使用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.x
和thing.y
应始终使用Math.round()
舍入为整数。
答案 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.x
和thing.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对象中创建任何代码,将它们视为不可变的。