英文原版:https://guides.emberjs.com/v2.13.0/object-model/computed-properties/
计算属性是个什么鬼?
简而言之,计算属性就是可以把属性的值声明为一个函数。当你定义了一个计算属性的时候,并且当你调用这个属性的时候,Ember会自动为你执行属性对应的函数。你可以完全把它当做普通属性,或者是静态属性那么去用。
这可以让你非常方便的一次性操作多个属性,并得到一个新的结果。
开始行动
我们来弄个简单的例子。现在我们有一个Person对象,这个对象有firstName和lastName两个属性,但是我们现在想要有这两个属性组成的全名。并且这个全名显示的结果会随着firstName和lastName的改变而改变:
Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', function() {
let firstName = this.get('firstName');
let lastName = this.get('lastName');
return `${firstName} ${lastName}`;
})
});
let ironMan = Person.create({
firstName: 'Tony',
lastName: 'Stark'
});
ironMan.get('fullName'); // "Tony Stark"
属性fullName就是声明的计算属性,firstName和lastName作为它的依赖。当你第一次使用fullName属性的时候,computed()会被调用并且将回调函数中的结果缓存。当你下次直接调用fullName的时候,它的结果会直接从缓存中获取。如果你改变了它的任何一个依赖,即:firstName和lastName的值,那么缓存就会失效,这时候computed()会重新执行,这时你将得到新的结果。
用一个对象声明多个依赖
在上面的例子中,fullName属性依赖了2个属性。
…
fullName: Ember.computed('firstName', 'lastName', function() {
let firstName = this.get('firstName');
let lastName = this.get('lastName');
return `${firstName} ${lastName}`;
})
…
我们也可以使用括号表达式来申明依赖,就像下面这样:
…
fullName: Ember.computed('{firstName,lastName}', function() {
let firstName = this.get('firstName');
let lastName = this.get('lastName');
return `${firstName} ${lastName}`;
})
…
这么声明,会在你的依赖是json对象的时候尤其有用:
let obj = Ember.Object.extend({
baz: {foo: 'BLAMMO', bar: 'BLAZORZ'},
something: Ember.computed('baz.foo', 'baz.bar', function() {
return this.get('baz.foo') + ' ' + this.get('baz.bar');
})
});
括号表达式方式:
let obj = Ember.Object.extend({
baz: {foo: 'BLAMMO', bar: 'BLAZORZ'},
something: Ember.computed('baz.{foo,bar}', function() {
return this.get('baz.foo') + ' ' + this.get('baz.bar');
})
});
计算属性链
你还可以把计算属性当做依赖,这样会形成一个计算属性链。现在再添加一个description计算属性:
Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
country: null,
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
}),
description: Ember.computed('fullName', 'age', 'country', function() {
return `${this.get('fullName')}; Age: ${this.get('age')}; Country: ${this.get('country')}`;
})
});
let captainAmerica = Person.create({
firstName: 'Steve',
lastName: 'Rogers',
age: 80,
country: 'USA'
});
captainAmerica.get('description'); // "Steve Rogers; Age: 80; Country: USA"
动态更新
计算属性,默认的会监听它所依赖的属性的变化,并且会在依赖发生变化时被调用并进行自动更新。下面作一个演示:
captainAmerica.set('firstName', 'William');
captainAmerica.get('description'); // "William Rogers; Age: 80; Country: USA"
可以看到,fullName因为firstName的变化而变化,进而又引起description的变化。
对依赖的属性做任何改变都会引起依赖链上的其他计算属性的变化,直到依赖链的末尾。
设置计算属性
你也可以配置当你操作计算属性的时候需要它干什么。当你要给它一个值的时候(此时会调用setter方法;相反的,会调用getter方法),它会需要你传入一个key和对应的value给它。同时,你需要把你想要缓存在计算属性中的那个值return:
Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', {
get(key) {
return `${this.get('firstName')} ${this.get('lastName')}`;
},
set(key, value) {
let [firstName, lastName] = value.split(/\s+/);
this.set('firstName', firstName);
this.set('lastName', lastName);
return value;
}
})
});
let captainAmerica = Person.create();
captainAmerica.set('fullName', 'William Burnside');
captainAmerica.get('firstName'); // William
captainAmerica.get('lastName'); // Burnside
计算属性宏
大多数你要定义的计算属性的形式都基本一样。不过Ember也提供一些宏,用来再某些特定的场景声明计算属性。
例子,下面这两个计算属性功能上时等价的:
Person = Ember.Object.extend({
fullName: 'Tony Stark',
isIronManLongWay: Ember.computed('fullName', function() {
return this.get('fullName') === 'Tony Stark';
}),
isIronManShortWay: Ember.computed.equal('fullName', 'Tony Stark')
});
查阅完整的计算属性宏,移步看一下这里。
本节完