簡單地來講,計算屬性就是將函數聲明爲屬性。其實就是就是在類擴展的時候爲類定義的屬性。html
Person = Ember.Object.extend({ firstName: null, lastName: null, // fullName 就是一個計算屬性 fullName: Ember.computed('firstName', 'lastName', function() { return this.get('firstName') + ", " + this.get('lastName'); }) }); // 實例化同時傳入參數 var piter = Person.create({ firstName: 'chen', lastName: 'ubuntuvim' }); console.log(piter.get('fullName')); // output >> chen, ubuntuvim
計算屬性其實就是一個函數,若是你接觸過就jQuery、Extjs相信你回很是熟悉,在這兩個框架中函數就是這麼定義的。只不過在Ember中,把這種函數當作屬性來處理,而且能夠經過get獲取函數的返回值。ubuntu
在Ember程序中,計算屬性還能調用另一個計算屬性,造成計算屬性鏈,也能夠用於擴展某個方法。在上一實例的基礎上增長一個description()方法。vim
Person = Ember.Object.extend({ firstName: null, lastName: null, age: null, county: null, // fullName 就是一個計算屬性 fullName: Ember.computed('firstName', 'lastName', function() { return this.get('firstName') + ", " + this.get('lastName'); }), description: Ember.computed('fullName', 'age', 'county', function() { return this.get('fullName') + " age " + this.get('age') + " county " + this.get('county'); }) }); // 實例化同時傳入參數 var piter = Person.create({ firstName: 'chen', lastName: 'ubuntuvim', age: 25, county: 'china' }); console.log(piter.get('description')); // output >> chen, ubuntuvim
當用戶使用set方法改變firstName的值,而後再調用get('description')獲得的值也是更新後的值。api
注意要把從新的屬性做爲參數傳入computed方法,要區別計算屬性的定義方法,定義的時候computed方法的最後一個參數是一個function,而重寫的時候最後一個參數是一個hash。數組
// 重寫計算屬性的get、set方法 Person = Ember.Object.extend({ firstName: null, lastName: null, // 重寫計算屬性fullName的get、set方法 fullName: Ember.computed('firstName', 'lastName', { get(key) { return this.get('firstName') + "," + this.get('lastName'); }, set(key, value) { // 這個官方文檔使用的代碼,可是我運行的時候出現 Uncaught SyntaxError: Unexpected token [ 這個錯誤,不知道是不是缺乏某個文件,後續會補上; // console.log("value = " + value); // var [ firstName, lastName ] = value.split(/\s+/); var firstName = value.split(/\s+/)[0]; var lastName = value.split(/\s+/)[1]; this.set('firstName', firstName); this.set('lastName', lastName); } }), // 對於普通的屬性沒法重寫get、set方法 // firstName: Ember.computed('firstName', { // get(key) { // return this.get('firstName') + "@@"; // }, // set(key, value) { // this.set('firstName', value); // } // }) }); var jack = Person.create(); jack.set('fullName', "james kobe"); console.log(jack.get('firstName')); console.log(jack.get('lastName'));
咱們常常會遇到這種狀況:某個計算屬性值是依賴某個數組或者其餘對象的,好比在Ember JS 的todos這個例子中有這樣的一段代碼。app
export default Ember.Controller.extend({ todos: [ Ember.Object.create({ isDone: true }), Ember.Object.create({ isDone: false }), Ember.Object.create({ isDone: true }) ], remaining: Ember.computed('todos.@each.isDone', function() { var todos = this.get('todos'); return todos.filterBy('isDone', false).get('length'); }) });
計算屬性remaining的值就是依賴數組todos。在這裏還有個知識點:在上述代碼computed()方法裏有一個todos.@each.isDone這樣的鍵,裏面包含了一個特別的鍵「@each」(後面還會看到更特別的鍵「[]」)。須要注意的是這種鍵不能嵌套而且是隻能獲取一個層次的屬性。好比todos.@each.foo.name(獲取多層次屬性,這裏是先獲得foo再獲取name)或者todos.@each.owner.@each.name(嵌套)這兩種方式都是不容許的。「todos.@each.foo.name」。框架
在以下4種狀況Ember會自動更新綁定的計算屬性值:函數
1. 在todos數組中任意一個對象的isDone屬性值發生變化的時候;網站
2. 往todos數組新增元素的時候;this
3. 從todos數組刪除元素的時候;
4. 在控制器中todos數組被改變爲其餘的數組的時候;
好比下面代碼演示的結果;
Task = Ember.Object.extend({ isDone: false // 默認爲false }); WorkerLists = Ember.Object.extend({ // 定義一個Task對象數組 lists: [ Task.create({ isDone: false }), Task.create({ isDone: true }), Task.create(), Task.create({ isDone: true }), Task.create({ isDone: true }), Task.create({ isDone: true }), Task.create({ isDone: false }), Task.create({ isDone: true }) ], remaining: Ember.computed('lists.@each.isDone', function() { var lists = this.get('lists'); // 查詢屬性isDone值爲false的對象,並返回其數量 return lists.filterBy('isDone', false).get('length'); }) }); // 以下代碼使用到的API請查看:http://emberjs.com/api/classes/Ember.MutableArray.html var wl = WorkerLists.create(); // 全部isDone屬性值未作任何修改 console.log('1,>> Not complete lenght is ' + wl.get('remaining')); // output 3 var lists = wl.get('lists'); // 獲得對象內的數組 // ----- 演示第一種狀況: 1. 在todos數組中任意一個對象的isDone屬性值發生變化的時候; // 修改數組一個元素的isDone的 值 var item1 = lists.objectAt(3); // 獲得第4個元素 objectAt()方法是Ember爲咱們提供的 // console.log('item1 = ' + item1); item1.set('isDone', false); console.log('2,>> Not complete lenght is ' + wl.get('remaining')); // output 4 // --------- 2. 往todos數組新增元素的時候; lists.pushObject(Task.create({ isDone: false })); //新增一個isDone爲false的對象 console.log('3,>> Not complete lenght is ' + wl.get('remaining')); // output 5 // --------- 3. 從todos數組刪除元素的時候; lists.removeObject(item1); // 刪除了一個元素 console.log('4,>> Not complete lenght is ' + wl.get('remaining')); // output 4 // --------- 4. 在控制器中todos數組被改變爲其餘的數組的時候; // 建立一個Controller TodosController = Ember.Controller.extend({ // 在控制器內定義另一個Task對象數組 todosInController: [ Task.create({ isDone: false }), Task.create({ isDone: true }) ], // 使用鍵」@each.isDone「遍歷獲得的filterBy()方法過濾後的對象的isDone屬性 remaining: function() { // remaining()方法返回的是控制器內的數組 return this.get('todosInController').filterBy('isDone', false).get('length'); }.property('@each.isDone') // 指定遍歷的屬性 }); todosController = TodosController.create(); var count = todosController.get('remaining'); console.log('5,>> Not complete lenght is ' + count); // output 1
上述的狀況中,咱們對數組對象的是關注點是在對象的屬性上,可是實際中每每不少狀況咱們並不關係對象內的屬性是否變化了,而是把數組元素做爲一個總體對象處理,相比上述的代碼咱們只關心數組對象元素的變化,而不是對象的isDone屬性的變化。在這種狀況你能夠看看下面例子,在例子中使用鍵「[]」代替鍵「@each.foo」。從鍵的變化也能夠看出他們的不一樣之處。
Task = Ember.Object.extend({ isDone: false, // 默認爲false name: 'taskName', // 爲了顯示結果方便,重寫toString()方法 toString: function() { return '[name = '+this.get('name')+', isDone = '+this.get('isDone')+']'; } }); WorkerLists = Ember.Object.extend({ // 定義一個Task對象數組 lists: [ Task.create({ isDone: false, name: 'ibeginner.sinaapp.com' }), Task.create({ isDone: true, name: 'i2cao.xyz' }), Task.create(), Task.create({ isDone: true, name: 'ubuntuvim' }), Task.create({ isDone: true , name: '1527254027@qq.com'}), Task.create({ isDone: true }) ], index: null, indexOfSelectedTodo: Ember.computed('index', 'lists.[]', function() { return this.get('lists').objectAt(this.get('index')); }) }); var wl = WorkerLists.create(); // 全部isDone屬性值未作任何修改 var index = 1; wl.set('index', index); console.log('Get '+wl.get('indexOfSelectedTodo').toString()+' by index ' + index);
Ember.computed這個組件中有不少使用鍵「[]」實現的方法。當你想建立一個計算屬性是數組的時候特別適用。你可使用Ember.computed.map來構建你的計算屬性。
const Hamster = Ember.Object.extend({ chores: null, excitingChores: Ember.computed('chores.[]', function() { //告訴Ember chores是一個數組 return this.get('chores').map(function(chore, index) { //return `${index} --> ${chore.toUpperCase()}`; // 可使用${}表達式,而且在表達式內能夠直接調用js方法 return `${chore}`; //返回元素值 }); }) }); // 爲數組賦值 const hamster = Hamster.create({ // 名字chores要與類Hamster定義指定數組的名字一致 chores: ['First Value', 'write more unit tests'] }); console.log(hamster.get('excitingChores')); hamster.get('chores').pushObject("Add item test"); //add an item to chores array console.log(hamster.get('excitingChores'));
Ember還提供了另一種方式去定義數組類型的計算屬性。
const Hamster = Ember.Object.extend({ chores: null, excitingChores: Ember.computed('chores.[]', function() { return this.get('chores').map(function(chore, index) { //return `${index} --> ${chore.toUpperCase()}`; // 可使用${}表達式,而且在表達式內能夠直接調用js方法 return `${chore}`; //返回元素值 }); }) }); // 爲數組賦值 const hamster = Hamster.create({ // 名字chores要與類Hamster定義指定數組的名字一致 chores: ['First Value', 'write more unit tests'] }); console.log(hamster.get('excitingChores')); hamster.get('chores').pushObject("Add item test"); //add an item to chores array console.log(hamster.get('excitingChores'));