imweb / Ques

An new architecture which deal with how to implement and use a component
http://miniflycn.github.io/Ques/
62 stars 14 forks source link

突然想起来有利用节点onpropertychange来模拟Object属性监听的实现= = #6

Closed miniflycn closed 9 years ago

miniflycn commented 9 years ago
<!DOCTYPE html>
<html>
<body>
<script>
var s = {},
    defineProperty = Object.defineProperty,
    needFix = false;

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, scope) {
        'use strict';
        var i, len;
        for (i = 0, len = this.length; i < len; ++i) {
            if (i in this) {
                fn.call(scope, this[i], i, this);
            }
        }
    };
}

if (!Object.keys) {

    Object.keys = function (o) {

        if (o !== Object(o)) {
            throw new TypeError('Object.keys called on a non-object');
        }

        var k = [],
            p;

        for (p in o) {

            // Use direct access, just in case this object has overridden the hasOwnProperty method which does something different.
            // Also as it wont go through the prototype chain to find the method, it should be quicker
            // Finally hasOwnProperty is set on the lowest level prototype 'Object' which all object derive from. However Object.create(null) can be used to
            // create an object that has no base prototype, meaning hasOwnProperty would not exist (however this usage of Object.create is not recommended)
            if (Object.prototype.hasOwnProperty.call(o, p)) {
                k.push(p);
            }
        }

        return k;
    }
}

if (defineProperty) {
    try {
        defineProperty({}, '_', {
            value: 'x'
        });
    } catch (e) {
        needFix = true;
    }
    if (needFix) {
        if ('__defineGetter__' in s) {
            defineProperty = function (obj, prop, desc) {
                if ('value' in desc) {
                    obj[prop] = desc.value;
                }
                'get' in desc &&
                    obj.__defineGetter__(prop, desc.get);
                'set' in desc &&
                    obj.__defineSetter__(prop, desc.set);
            };
        } else {
            defineProperty = undefined;
        }
    }
}

function _createIEBindData(data, cb) {
    var res = document.createElement('fake');
    document.body.appendChild(res);
    Object.keys(data).forEach(function (key) {
        typeof data[key] === 'object' ?
            (res[key] = _createIEBindData(data[key], function (subKey, value, oldVal) { cb([key, subKey].join('.'), value, oldVal); })) :
            (res[key] = data[key]);
    });
    res.attachEvent('onpropertychange', function (e) {
        var name = e.propertyName,
            value = res[name];
        cb(name, value, data[name]);
        data[name] = value;
    });
    return res;
}

function _makedesc(data, prop, cb) {
    var value = data[prop];
    return {
        get: function () {
            return value;
        },
        set: function (s) {
            cb(prop, s, value);
            value = s;
        }
    }
}

function _createBindData(data, cb) {
    Object.keys(data).forEach(function (key) {
        if (typeof data[key] === 'object') {
            _createBindData(data[key], function (subKey, value, oldVal) { cb([key, subKey].join('.'), value, oldVal); });
        }
        defineProperty(data, key, _makedesc(
            data, key, cb
        ));
    })
    return data;
}

function bindData(data, cb) {
    return defineProperty ?
        _createBindData(data, cb) :
        _createIEBindData(data, cb);
}

var data = bindData({ test: 'test', obj: { msg: 'hello' } }, function (key, value, oldVal) {
    console.log(
        'key === ' + key + '; ', 
        'value === ' + value + '; ', 
        'oldVal === ' + oldVal + '; '
    );
});

data.test = 123;
data.obj.msg = 'nihao';
</script>
</body>
</html>
miniflycn commented 9 years ago

Branchmarks: http://jsperf.com/watch-property