英文原址:http://emberjs.com/guides/object-model/computed-properties/
什么是可计算型属性?
概括的说,计算型属性让你将方法定义为属性。你通过将属性定义成一个方法来创建一个可计算型属性,当你使用它时Ember会自动调用该方法来计算该属性。然后你就可以像使用其他的静态属性同样的方式来使用它了。
使用一个或者多个普通属性,转换或者处理它们的值来创建一个新的值,是非常方便的。
使用可计算型属性
我们先从一个简单的例子开始:
App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var ironMan = App.Person.create({
firstName: "Tony",
lastName: "Stark"
});
ironMan.get('fullName') // "Tony Stark"
请注意fullName方法调用了property方法,这种使用方式声明了该方法是一个可计算型的属性,指定的那些参数告诉了Ember这个可计算型属性依赖firstName和lastName属性。
每次你访问fullName属性,这个方法就会被调用并且返回该方法的返回值,此处是简单的调用“firstName + lastName"。
其他调用方法
此时,你可能会奇怪为什么你可以对一个function调用property函数,这是因为Ember扩展了function原型,可以点击此处了解更多。如果你不想使用这种扩展的方式但仍然希望获得一样的行为,你可以这么做:
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + ' ' + this.get('lastName');
})
链接可计算型属性
你可以使用可计算型属性来定义新的可计算型属性。让我们给之前的例子添加一个description的可计算型属性,它会使用fullName属性,并且添加一些其他的新属性:App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
country: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
description: function() {
return this.get('fullName') + '; Age: ' + this.get('age') + '; Country: ' + this.get('country');
}.property('fullName', 'age', 'country')
});
var captainAmerica = App.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"
这里firstName属性的改变会被fullName属性观察到,然后fullName的改变也会被description属性观察到。
设置任何被其他属性依赖的属性的值都会导致任何依赖它的可计算属性的变化,这会形成一个链式反应逐级追溯所有关联在一起的计算型属性。
设置计算型属性
你还可以定义当你设置一个计算型属性的值时Ember应该怎么做。如果你试图设置一个计算型属性,调用时需要传入key(属性名字),value(你想要设置的新值),previous value(先前的旧值)。
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: function(key, value, previousValue) {
// setter
if (arguments.length > 1) {
var nameParts = value.split(/\s+/);
this.set('firstName', nameParts[0]);
this.set('lastName', nameParts[1]);
}
// getter
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var captainAmerica = App.Person.create();
captainAmerica.set('fullName', "William Burnside");
captainAmerica.get('firstName'); // William
captainAmerica.get('lastName'); // Burnside
无论你是设置它的值还是访问它的值,Ember都会调用该计算型属性对应的方法,因此如果你打算让一个计算型属性也作为一个setter方法,那么你必须检查传入的参数个数来决定当前它是作为getter使用还是作为setter使用。请注意,如果一个值从setter中返回,这个值会被作为该属性的值缓存起来。