2017-04-07 127 views
0

使用JS getter和setter方法,我的目標,以創建下列API的情況:ES6:如何擁有一個getter /爲對象和setter其屬性

// 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()四捨五入爲整數。

+1

你看過如何定義類。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes – funcoding

+1

'thing'返回一個新對象。 –

+0

是的,這是一個類的一部分。還是你建議我把類變成一個類實例?因爲,在我的項目中,它已經是,實際上...... – suncannon

回答

3

如果你必須使用getters和setter,那麼一個相對簡單的解決方案就是將xy定義爲getters和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; 
    } 
} 
+0

這看起來很有前途!我會嘗試一下......緩存對象是否意味着基本上將它創建爲先前的變量?我在尋找需要「東西」,「東西」還是「__東西」?我可以看到這會如何變得醜陋,但在這個特定情況下可能會有用。 – suncannon

+0

查看我添加的更完整的示例。 –

+0

這很有用。這有點棘手,因爲對我來說'_thing'已經是另一個類實例了......但是我認爲你所描述的額外抽象層可以解決這個問題。在吸氣劑中返回一個吸氣劑和二聚體看起來是正確的。一個修正 - 我想你想在第10行使用'self._x',是嗎? – suncannon

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

代理允許你趕上上的屬性獲取或設置操作。

注意事項: IE目前並不支持代理服務器。如果我的CDN是Google's Proxy polyfill,我會將它添加到片段中,但我不知道。此外,如果您使用Babel,那麼有babel-plugin-proxy

+1

我也會嘗試這個,但是當我運行代碼片段時它會產生一個錯誤(「腳本錯誤」)。你知道爲什麼嗎? – suncannon

+1

當你在這裏運行它?我看到16和13作爲輸出 – mikeapr4

+0

我在Chrome和FF中運行它,它工作正常,但它看起來像在IE中它需要一個polyfill,堅持,我會看看如果我能找到一個。 – mikeapr4

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; 

由於我們回到一個簡單的地圖位置吸氣,position.x只是分配給返回的副本,並不會改變Foo的實際位置。解決這個問題的方法之一是讓位置獲取器返回一個更智能的對象,該對象具有對foo實例和適當的getter/setter的引用。這將允許操作的方式:

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

bar.position吸氣劑都將返回一個僅僅充當bar的x/y的特性的視圖中的對象。然後,foo.position setter會將bar的x/y屬性複製到其私有存儲中。說得通。 bar.x += 10廣告僅限於bar的位置。

但是,下列情況會非常混亂:

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

這就造成了錯覺,溫度是foo.position備份副本,但事實並非如此。這是一個觀點。只要foo的職位發生變化,我們就會失去這些數據。沒有簡單的方法來複制位置。

你可以試着讓你的position對象實際上存儲數據的副本以及對原始數據的引用,這樣你就可以同時進行設置和獲取......這是一個無窮無盡的問題。

但是在這一點上,你的糖語法正在使一切難以維護以及效率更低。

所以,我並沒有這麼做,而是讓x和y getter/setter在foo/bar對象上。我也會在foo/bar對象內部處理任何代碼,就像它們是不可變的一樣。

相關問題