本节对第三节的代码进行重构一下。
我们发现$.computed其实也是一种$.observable,因此可以写成这样:
var
validValueType = $.oneObject(
"Null,NaN,Undefined,Boolean,Number,String"
)
$.dependencyChain = (
function
() {
var
_frames = [];
return
{
begin:
function
(ret) {
_frames.push(ret);
},
end:
function
() {
_frames.pop();
},
collect:
function
(self) {
if
(_frames.length > 0) {
self.list = self.list || [];
var
fn = _frames[_frames.length - 1];
if
( self.list.indexOf( fn ) >= 0)
return
;
self.list.push(fn);
}
}
};
})();
$.notifyUpdate =
function
(observable){
var
list = observable.list
if
($.type(list,
"Array"
)){
for
(
var
i = 0, el; el = list[i++];){
el();
//通知顶层的computed更新自身
}
}
}
$.computed =
function
(obj, scope){
var
args
//构建一个至少拥有getter,scope属性的对象
if
(
typeof
obj ==
"function"
){
args = {
getter: obj,
scope: scope
}
}
else
if
(
typeof
obj ==
"object"
&& obj && obj.getter){
args = obj
}
return
$.observable(args,
true
)
}
$.observable =
function
(old, isComputed){
var
cur, getter, setter, scope
function
ret(neo){
var
set;
//判定是读方法还是写方法
if
(arguments.length){
//setter
neo =
typeof
setter ===
"function"
? setter.call( scope, neo ) : neo
set =
true
;
}
else
{
//getter
if
(
typeof
getter ===
"function"
){
$.dependencyChain.begin(ret);
//只有computed才在依赖链中暴露自身
neo = getter.call( scope )
console.log(neo+
"!!!!!!!!!!"
)
//用来查看执行情况
$.dependencyChain.end()
}
else
{
neo = cur
}
$.dependencyChain.collect(ret)
//将暴露到依赖链的computed放到自己的通知列表中
}
if
(cur !== neo ){
cur = neo;
$.notifyUpdate(ret)
}
return
set ? ret : cur
}
if
( isComputed ==
true
){
getter = old.getter; setter = old.setter; scope = old.scope;
ret();
//必须先执行一次
}
else
{
old = validValueType[$.type(old)] ? old : void 0;
cur = old;
//将上一次的传参保存到cur中,ret与它构成闭包
ret(old);
//必须先执行一次
}
return
ret
}
function
MyViewModel() {
this
.firstName = $.observable(
'Planet'
);
this
.lastName = $.observable(
'Earth'
);
this
.fullName = $.computed({
getter:
function
() {
return
this
.firstName() +
" "
+
this
.lastName();
},
setter:
function
(value) {
var
lastSpacePos = value.lastIndexOf(
" "
);
if
(lastSpacePos > 0) {
// Ignore values with no space character
this
.firstName(value.substring(0, lastSpacePos));
// Update "firstName"
this
.lastName(value.substring(lastSpacePos + 1));
// Update "lastName"
}
},
scope:
this
});
this
.card = $.computed(
function
(){
return
this
.fullName() +
" 屌丝"
},
this
);
this
.wordcard = $.computed(
function
(){
return
this
.card() +
"工作卡 "
},
this
)
this
.wordcardA = $.computed(
function
(){
return
this
.wordcard() +
"A "
},
this
)
}
window.onload =
function
(){
var
model =
new
MyViewModel();
$.log(
"=================="
)
model.lastName(
"last"
);
$.log(
"=================="
)
}
|
打印如下:
Planet Earth 屌丝!!!!!!!!!!
Planet Earth 屌丝工作卡 !!!!!!!!!!
Planet Earth!!!!!!!!!!
Planet Earth 屌丝!!!!!!!!!!
Planet Earth 屌丝工作卡 !!!!!!!!!!
Planet Earth 屌丝工作卡 A !!!!!!!!!!
==================
Planet last!!!!!!!!!!
Planet last!!!!!!!!!!
Planet last 屌丝!!!!!!!!!!
Planet last!!!!!!!!!!
Planet last 屌丝!!!!!!!!!!
Planet last 屌丝工作卡 !!!!!!!!!!
Planet last!!!!!!!!!!
Planet last 屌丝!!!!!!!!!!
Planet last 屌丝工作卡 !!!!!!!!!!
Planet last 屌丝工作卡 A !!!!!!!!!!
==================
|
依赖链发生效力了!不过感觉糟极了,有许多通知是没必要的。我们在$.notifyUpdate与$.observable添加缓存机制看看:
$.notifyUpdate =
function
(observable){
var
list = observable.list;
if
($.type(list,
"Array"
)){
for
(
var
i = 0, el; el = list[i++];){
delete
el.cache;
//清除缓存
el();
//通知顶层的computed更新自身
}
}
}
//**********************略***************
$.observable =
function
(old, isComputed){
//**********************略***************
function
ret(neo){
var
set;
//判定是读方法还是写方法
if
(arguments.length){
//setter
neo =
typeof
setter ===
"function"
? setter.apply( scope, arguments ) : neo
set =
true
;
}
else
{
//getter
if
(
typeof
getter ===
"function"
){
$.dependencyChain.begin(ret);
//只有computed才在依赖链中暴露自身
if
(
"cache"
in
ret){
neo = ret.cache;
//从缓存中读取,防止递归
}
else
{
neo = getter.call( scope );
ret.cache = neo;
//保存到缓存
console.log(neo+
"!!!!!!!!!!"
);
//
}
$.dependencyChain.end()
}
else
{
neo = cur
}
$.dependencyChain.collect(ret)
//将暴露到依赖链的computed放到自己的通知列表中
}
if
(cur !== neo ){
cur = neo;
$.notifyUpdate(ret);
}
return
set ? ret : cur
}
//**********************略***************
if
( isComputed ==
true
){
getter = old.getter; setter = old.setter; scope = old.scope;
ret();
//必须先执行一次
}
else
{
old = validValueType[$.type(old)] ? old : void 0;
cur = old;
//将上一次的传参保存到cur中,ret与它构成闭包
ret(old);
//必须先执行一次
}
return
ret
}
|
这时它的情况就好多了:
Planet
Earth
Planet Earth!!!!!!!!!!
Planet Earth 屌丝!!!!!!!!!!
Planet Earth 屌丝工作卡 !!!!!!!!!!
Planet Earth 屌丝工作卡 A !!!!!!!!!!
==================
Planet last!!!!!!!!!!
Planet last 屌丝!!!!!!!!!!
Planet last 屌丝工作卡 !!!!!!!!!!
Planet last 屌丝工作卡 A !!!!!!!!!!
==================
|