IFE_02_dynamicDataBinding_02

总结:

  • 之前的代码有误,忘记在defineProperty 之后给属性赋值,会导致所有属性值相同

  • 缺点:

    • $watch 只能监测data 的第一层属性,主要原因是在循环defineProperty 时无法获取当前属性的全部引用链,比如data.name.firstName 在循环中只能取到'firstName' ,目前没有想出办法拿到'data_name_firstName'
  • 观察值模式

    • 主要利用CustomEvent ,其中dispatchEvent 没太搞懂,为什么放在$watch 中就无法运行回调?放在setter 中就可以。
    • 目前的理解是dispatchEvent 是脚本内部的触发,放在setter 中就是每次设置值时触发,而放在$watch 中就相当于只有执行$watch 的时候触发

代码:

<!DOCTYPE html>
<html>
<head>
    <title>dymanic_data_binding_02</title>
    <meta charset="utf-8">
    <style type="text/css">
    </style>

    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/default.min.css" />
</head>
<body>
    <ol>要求:
        <li>
            <h3>如果传入参数对象时一个“比较深”的对象(也就是其属性值也可能是对象),那该怎么办?</h3>
            <pre><code>
                let obj = new Observer({
                    a: 1,
                    b: 2,
                    c: {
                        d: 3,
                        e: 4
                    }
                });

                obj.data.c.d // 你访问了 d
                obj.data.c.e = 100; // 你设置了 e,新的值为 100
                obj.data.a // 你访问了 a
                obj.data.b = 'science'; // 你设置了 b,新的值为 science
            </code></pre>
        </li>
        <li>
            <h3>如果设置新的值是一个对象的话,新设置的对象的属性是否能继续响应getter和setter?</h3>
            <pre><code>
                let app1 = new Observer({
                    name: 'youngwind',
                    age: 25
                });

                app1.data.name = {
                    lastName: 'liang',
                    firstName: 'shaofeng'
                }

                app1.data.name.lastName // 你访问了 lastName
                app1.data.name.firstName = 'lalala'; // 你设置了 firstName,新的值为 lalala
            </code></pre>
        </li>
        <li>
            <h3>考虑传递回调函数。在实际应用中,当特定数据发生改变的时候,我们是希望做出一些特定的事情的,而不是每一次都只能打印出一些信息。所以,我们需要支持传入回调函数的功能。</h3>
            <pre><code>
                let app1 = new Observer({
                    name: 'youngwind',
                    age: 25
                });

                app1.$watch('age', function (age) {
                    console.log(`我的年纪变了,现在已经是:${age}岁了`);
                });

                app1.data.age = 100; // 我的年纪变了,现在已经是:100岁了
            </code></pre>
        </li>
    </ol>

<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>
<script type="text/javascript">
    hljs.initHighlightingOnLoad();

    function Observer (data) {
        this.watchEvents = {};

        this.defineProperty(this, 'data', data);
    }

    Observer.prototype.defineProperty = function (obj, key, data) {
        if (_getType(data) !== 'object') throw 'wrong data type';

        let _this = this;

        Object.keys(data).forEach(function (v, i) {
            let dataVal;

            if (_getType(data[v]) === 'object') {
                _this.defineProperty(obj[key], v, data[v]);
            } else {
                if (_getType(obj[key]) !== 'object') {
                    delete obj[key];
                    obj[key] = {};
                }

                Object.defineProperty(obj[key], v, {
                    get: function () {
                        // console.log(`你访问了 ${v}`);
                        return dataVal;
                    },
                    set: function (value) {
                        if (_getType(value) === 'object') {
                            _this.defineProperty(obj[key], v, value);
                        } else {
                            let oldValue = obj[key][v];

                            console.log(`你设置了 ${v},新的值为 ${value}`);

                            dataVal = value;

                            _this.watchEvents[v] = _polyfillCustomEvent(`$watch_${v}`, {
                                detail: {
                                    value: value,
                                    oldValue: oldValue
                                }
                            });

                            document.dispatchEvent(_this.watchEvents[v]);
                        }
                    },
                    enumerable: true,
                    configurable: true
                });

                obj[key][v] = data[v];
            }

        }, obj);
    }

    Observer.prototype.$watch = function (key, callback) {
        let _this = this;

        // $watch 仅对 data 的第一层属性有效
        document.addEventListener(`$watch_${key}`, function (e) {
            (e.detail.oldValue !== e.detail.value) && callback(e.detail.value);
        })
    };

    function _polyfillCustomEvent (event, params) {
        if (!CustomEvent) {
            function CustomEvent (event, params) {
                params = params || {
                    bubbles: false,
                    cancelable: false,
                    detail: undefined
                };

                let evt = document.createEvent('CustomEvent');
                evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
                return evt;
            }

            CustomEvent.prototype = window.Event.prototype;
        }
        return new CustomEvent(event, params);
    }


    function _getType (obj) {
        return Object.prototype.toString.call(obj).match(/ .+(?=\])/)[0].trim().toLowerCase();
    }
</script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值