dojo源码阅读之dojo/Stateful

dojo/Stateful是dojo中的一个基类,提供了能够观测对象属性变化的功能,Stateful 使用文档

其基本用法如下:

var s = new Stateful({foo:8})
s._fooSetter = function(value){
  this.foo = value;
};
s.watch("foo", function(name, oldValue, newValue){
   console.log(`foo的值由${oldValue}变为${newValue}`)
})

执行 s.set("foo", 9),  s._fooSetter就会被调用, 同时控制台会输出: ”foo的值由8变为9“

Stateful是如何做到上述功能的呢,Stateful.set方法, 可以看到当调用 Stateful实例的set方法时,set方法会根据要传入的name计算出setter方法, 如set('foo', 9)会找到_fooSetter方法并执行,如果使用了watch方法观察foo的变化,那么对应的callback就会被调用。

watch是如何实现的呢。Stateful.watch方法。以下面代码为例

 s = new Stateful()
 watchFun1 = function(name, oldValue, newValue){
     console.log(`fun1 is invoked`);
 };
 watchFun2 = function(name, oldValue, newValue){
     console.log(`fun2 is invoked`);
 };
 s.watch("foo", watchFun1)
 s.watch("foo", watchFun2)

watch方法的实现步骤大致如下:

1, 定义_watchCallbacks 方法(一个Stateful实例只会被定义一次)。

    this._watchCallbacks  = function(name, oldValue, value){

            .....//根据name找到对应的listener函数并执行。如foo对应的watchFun1和watchFun2.

     }

2, this._watchCallbacks._foo = [watchFun1, watchFun2]

_changeAttrValue方法

_changeAttrValue方法用来直接改变Stateful实例的属性,而不属性对应的setter方法。

如s._changeAttrValue("foo", 9)会直接设置s.foo为9而不调用s._fooSetter, 如果使用s.set("foo", 9)则会调用。

什么情况下会用到_changeAttrValue方法呢,当Stateful实例有两个互相link的属性时。如s.bar = s.foo * 2;

当s.bar改变时s.foo也要变,而s.foo改变时s.bar也要跟着改变。这样就会形成一个无限循环。如:

 s = new Stateful({
        foo: 1
    });
    //bar = foo * 2
    s._fooSetter = function(name, value) {
        this.foo = value;
        this.set("bar", value * 2);
        console.log("s._fooSetter is invoked");
    }

    s._barSetter = function(name, value) {
        this.bar = value;
        this.set("foo", value / 2);
        console.log("s._barSetter is invoked");
    }

如果使用_changeAttrValue就可以避免这个问题。如下:

s._fooSetter = function(value) {
        this.foo = value;
        this._changeAttrValue("bar", value * 2);
        console.log("s._fooSetter is invoked");
    }

    s._barSetter = function(value) {
        this.bar = value;
        this._changeAttrValue("foo", value / 2);
        console.log("s._barSetter is invoked");
    } 

你可以像上面例子中直接Stateful实例化一个对象,但一个更好的方式是继承Stateful来实现一个子类再实例化对应的对象, 如下:

MyStateful = new declare([Stateful], {
        foo:1,
        _fooSetter: function(value){
            this.foo = value;
            this._changeAttrValue("bar", value * 2);
        },
        bar: 2,
        _barSetter: function(value){
            this.bar = value;
            this._changeAttrValue("foo", value / 2);
        }
    });

    s = new MyStateful();


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值