Emberjs之ComputedProperty

 

   計算屬性,如下簡稱CP。簡單歸納來說,就是在須要屬性值的時候計算一個Function,並將Function返回的值保存在屬性中,當第二次獲取屬性值時,若是發現屬性並未改變則直接讀取屬性,若是屬性依賴的事物發生改變,則從新計算該屬性值。html

下面用C#實現基本的CP原理(CP其實更復雜一些,但這樣一個簡單的例子有助於有一個基本的CP理解):前端

private object _myCar;                                    // 內部緩存變量
public bool IsDirty;                                      // MyCar屬性依賴的對象

public object MyCar {
    get {
          if(_isDirty) {                                           
               _myCar = 4S.BuyANewCar('Audio A4');        // 從新計算屬性值並保存
          }
          return _myCar;
    }
}                                        

 

文章索引

JS前端框架之Ember.js系列git

 

1. What is CP?

  In a nutshell, computed properties let you declare functions as properties. You create one by defining a computed property as a function, which Ember will automatically call when you ask for the property. github

  簡而言之,計算屬性讓你能夠把函數方法聲明爲屬性,你經過定義一個計算屬性做爲函數方法時,Ember將自動調用當訪問屬性時。shell

1. 第一種寫法:api

App.Person = Ember.Object.extend({  
  firstName: null,
  lastName: null,

  fullName: function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  }.property('firstName', 'lastName')                // fullName是一個依賴屬性,當firstName或者lastName發生改變時,而且當訪問fullName是,從新執行function,不然返回已緩存的fullName值。
});

var ironMan = App.Person.create({
  firstName: "Tony",
  lastName:  "Stark"
});

ironMan.get('fullName'); // "Tony Stark"

2. 第二種寫法:(推薦寫法數組

  CP也能夠這樣寫,建議以下寫法,避免「禁用」function的property擴展帶來的問題。緩存

  [Prototype Extensions](http://emberjs.com/guides/configuring-ember/disabling-prototype-extensions/)
 fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  })

  Ember.js v1.12 更新帶有Set和get方法的CP:前端框架

  fullName: Ember.computed("firstName", "lastName", {
    get: function() { return this.get("firstName") + " " + this.get("lastName"); }, set: function(key, newName) { var parts = newName.split(" "); this.setProperties({ firstName: parts[0], lastName: parts[1] }); return newName; } });

 

3. 第三種寫法:框架

  // An array of Ember.Table.Row computed based on `content`
  bodyContent: Ember.computed(function() {
    return RowArrayController.create({
      target: this,
      parentController: this,
      container: this.get('container'),
      itemController: Row,
      content: this.get('content')
    });
  }).property('content.[]', '_reloadBody'),

 

2. CP中名詞描述定義 

2.1 CP:Computed Property

2.2 CP屬性:上文例子中的‘fullName’。

2.3 CP所依賴的源屬性:上文例子中的‘firstName’、‘lastName’。

2.4 CP的回調方法:上文例子中的function(){......}方法。

2.5 CP屬性的Setter/Getter

 

3. CP重要原則(特性)

3.1 只有當獲取或設置CP屬性時,纔可能會觸發CP的回調方法,也就是說CP屬性是屬於‘懶加載’的方式(使用時計算行爲)。

3.2 當CP屬性依賴於.property('person.name', 'person.age')時,當person.name、person.age或person自己發生改變時改變(鏈式依賴)。

3.3 當CP屬性依賴於.property('columns.@each.isLoaded')時:

  • columns裏面任何一個元素的isLoaded屬性發生變化。
  • columns增長元素或者刪除子元素。
  • columns數組自己被從新賦值。
  • 不能依賴@each.owner.@each.name

3.4 當CP屬性依賴於.property('columns.@each')時:

  • 當columns增長或刪除元素。
  • 當columns自身被替換或從新賦值。

3.5 當CP屬性依賴於.property('columns.[]')時:

  與3.4 綁定.property('columns.@each') 行爲相同。

3.6 當經過set方法設置CP屬性時,而後調用get方法獲取CP屬性,則不調用CP回調,set時值被緩存。(CP屬性被覆蓋)

3.7 當存在兩個互相依賴的CP屬性時,僅僅發生三次屬性變動。

3.8 原則上不要將CP的依賴屬性附着在另外一個CP屬性上。

3.9 當CP屬性依賴於對象列表時,例如.property('a.b.c.d')上時,節點上任意對象發生變化時,均會從新計算屬性。(鏈式依賴

4. CP宏定義

Ember.computed.empty: empty(屬性名)返回bool

Ember.computed.not: not(屬性名)返回bool

Ember.computed.alias:alias(屬性名),雙向綁定, alias不要依賴於一個CP.

Ember.computed.defaultTo: 若是CP屬性爲null,則讀取依賴屬性值一次

Ember.computed.match(屬性名, 匹配字符串)

Ember.computed.gt(屬性名,數字)大於返回bool

Ember.computed.gte(屬性名,數字)大於或等於bool

Ember.computed.and(屬性名,屬性名) 並集

Ember.computed.or(屬性名, 屬性名) 交集

Ember.computed.collect( 數組 ) 匹配全部項,沒有相則爲null

Ember.computed.oneWay(屬性名) 單方向從到PC屬性. CP能夠被設置,但不會影響到CP依賴的屬性。

Ember.computed.readOnly(屬性名) CP屬性不容許被設置,但CP所依賴的源屬性更新CP值。

 更多宏定義請參考這裏:http://emberjs.com/api/classes/Ember.computed.html#method_alias

5. CP使用場景

5.1 在咱們使用的對象上,但願使用一個屬性值監聽一個或多個屬性的變動,或者CP屬性強依賴於某些屬性,並且還能緩存CP屬性值,減小性能損耗。(CP特性請參考3.1)

5.2 CP能夠依賴在一個對象的多個屬性上, 特別是綁定在集合元素上甚至監聽集合元素內部某一屬性,但層次有限制。例如.property('person{name,age}')或.property('pencilBox.[]', penBox.@each.color', penBox.@each)。(CP特性請參考3.二、3.三、3.4)

5.3 Ember.computed.alias做用於兩個強關聯對象的雙向綁定,並提供緩存機制。

5.4 經過CP來組合屬性,CP屬性回調中不能有邊界效應等循環、異步方法。

6. Q & A

6.1 當計算屬性(CP)設置爲getter和setter時,其CP回調函數觸發的場景:

  • 設置(set)CP屬性時,不管什麼時候都觸發CP回調方法。
  • 當獲取CP屬性時,若CP依賴屬性未發生變化,則不執行CP回調方法。

 

6.2 Ember.Computed(function(){}).property('xxxx') 與 function(){}.property('xxxx')區別:

  • 前者能夠用{get:function(){}, set: function(key, newName){}}的方式,沒必要在判斷Argument.length,實現了get、set的語法糖。
  fullName: Ember.computed("firstName", "lastName", {
    get: function() {
      return this.get("firstName") + " " + this.get("lastName");
    },
    set: function(key, newName) {
      var parts = newName.split(" ");
      this.setProperties({ firstName: parts[0], lastName: parts[1] });
      return newName;
    }
  });

 

6.3 CP之間的依賴行爲(cp1->cp2->x):

  • cp2從新計算後,並不會主動觸發cp1計算。
  • 若是x更新後,直接獲取cp1屬性,則cp2也被觸發計算。

 

6.4 Person.get('firstName')和Person.firstName之間的區別:

  當firstName爲(非計算屬性)普通屬性時,行爲相同。

  當firstName爲CP屬性時,前者能觸發CP回調方法,後者不能。

 

7. 示例代碼

[github示例代碼](https://github.com/Cuiyansong/ember-table-learnning/tree/master/ember-test/tests/unit)

 

Ember更新日誌:http://emberjs.com/deprecations/v1.x/#toc_deprecate-using-the-same-function-as-getter-and-setter-in-computed-properties 

Ember-Data: http://guides.emberjs.com/v1.13.0/object-model/computed-properties-and-aggregate-data/

相關文章
相關標籤/搜索