Emberjs之ComputedProperty
计算属性,以下简称CP。简单概括来讲,就是在需要属性值的时候计算一个Function,并将Function返回的值保存在属性中,当第二次获取属性值时,如果发现属性并未改变则直接读取属性,如果属性依赖的事物发生改变,则重新计算该属性值。
下面用C#实现基本的CP原理(CP其实更复杂一些,但这样一个简单的例子有助于有一个基本的CP理解):
private object _myCar; // 内部缓存变量
public bool IsDirty; // MyCar属性依赖的对象 public object MyCar {
get {
if(_isDirty) {
_myCar = 4S.BuyANewCar('Audio A4'); // 重新计算属性值并保存
}
return _myCar;
}
}
文章索引
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.
简而言之,计算属性让你可以把函数方法声明为属性,你通过定义一个计算属性作为函数方法时,Ember将自动调用当访问属性时。
1. 第一种写法:
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.2、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-Data: http://guides.emberjs.com/v1.13.0/object-model/computed-properties-and-aggregate-data/
Emberjs之ComputedProperty的更多相关文章
- Ember.js系列文章
JS前端框架之Ember.js系列文章 本文为文章索引,主要是罗列Ember.js的相关文章便于阅读. 相关演示代码:github for free. 基础篇 1. EmberJs之What|Why| ...
- EmberJs之数组绑定@each&[]
写在前面 好长时间没有写博客了,昨天花了些时间又整理了下之前发布过的<Ember.js之computed Property>文章,并创建了一个测试代码库,花了些时间,希望能使用测试代码的方 ...
- emberjs学习二(ember-data和localstorage_adapter)
emberjs学习二(ember-data和localstorage_adapter) 准备工作 首先我们加入ember-data和ember-localstorage-adapter两个依赖项,使用 ...
- emberjs学习一(环境和第一个例子)
code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent; } code, pre t ...
- EmberJs之使用Ember-Data
写在前面 最近比较忙,换了新工作还要学习很多全新的技术栈,并给自己找了很多借口来不去坚持写博客.常常具有讽刺意味的是,更多剩下的时间并没有利用而更多的是白白浪费,也许这就是青春吧,挥霍吧,这不是我想要 ...
- EmberJs之3W
写在前面 最近比较忙,换了新工作还要学习很多全新的技术栈,并给自己找了很多借口来不去坚持写博客.常常具有讽刺意味的是,更多剩下的时间并没有利用而更多的是白白浪费,也许这就是青春吧,挥霍吧,这不是我想要 ...
- emberjs初学记要
code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent; } code, pre t ...
- emberJS
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- quora 中有关angular与emberjs的精彩辩论
原贴地址,要注册才能看,这里只有国人翻译的一部分内容 本文源自于Quora网站的一个问题,作者称最近一直在为一个新的Rails项目寻找一个JavaScript框架,通过筛选,最终纠结于Angular. ...
随机推荐
- 【转】Win7 64bit Oracle 11g 使用PL/SQL Developer 连接时提示“SQL*Net not properly installed”
转载:http://www.cnblogs.com/xihuaodc/p/3189257.html 因为之前的Oracle不能用了,所以重新安装了64位的Oracle,安装一路正常 完了之后安装了P ...
- solr多词匹配搜索问题及解决
使用solr进行某较长词搜索时出现了一些问题,及解决方案. 1.问题:solr默认使用OR方式搜索,当搜索一个很长的次,比如“XX集团股份有限公司”,分词器分词后,使用OR方式匹配,会匹配到很多结果. ...
- mb_系列函数和普通字符函数的区别
<?php //phpinfo(); $str = 'abcdef'; echo strlen($str);// 6 echo '<br/>'; echo substr($str, ...
- GPU高性能计算-CUDA
前段时间有个同学的毕设是搞并行计算的,他基本不懂编程把我拉过去帮忙,我之前也没弄过,帮着搞了2天.先把代码贴上去,等有时间在把详细补充一些内容. CUDA编程主要是利用了显卡优越的并行计算能力,把一个 ...
- ceph实践: 搭建环境
作者:吴香伟 发表于 2014/09/26 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 本节主要参考官网的ADDING/REMOVING OSDS章节. 同步 ...
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
在上一篇文章<搭建高可用mongodb集群(二)—— 副本集> 介绍了副本集的配置,这篇文章深入研究一下副本集的内部机制.还是带着副本集的问题来看吧! 副本集故障转移,主节点是如何选举的? ...
- 找出一个二维数组中的"鞍点",即该位置上的元素在该行中最大,在该列中最小(也可能没有"鞍点"),打印有关信息.(提示:注意特殊情况:没鞍点或多个鞍点)
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { ][] = {}; ;i < ...
- loop 循环次数
在汇编中可以使用 loop 段地址:偏移地址 并配合 cx 达到循环执行的目的,但是在一些资料中看到说,cx 是循环的次数,我觉得这是不对的. 比如下面这段代码的作用是使得最终的 ax 中的值为 3 ...
- Linux系统布置java项目
一.远程服务器 Linux系统是没有Windows那样可视化的界面的,所以首先我们需要一个远程Linux服务器的软件,有好多种,比较好用的XShell,下载地址:http://rj.baidu.com ...
- JavaScript-navigator_userAgent-编写一段代码能够区分浏览器的主流和区分
1 userAgent:包含浏览器名称和版本号的字符串 <!DOCTYPE html> <html> <head lang="en"> < ...