08月18, 2016

mvvm的实现(未完)

我自认为是hold不住这个主题的,但既然写了,就努力去查相关资料,然后将这篇文章给完成(应该要等很久)。之所以有这个打算,是因为不管在工作中,或者面试中都可能会碰到这样的问题。

当然喽,吹牛逼谁都会。比如说回答:通过Object.defineProperty来实现,在低版本下用轮询(或脏检查),或者使用正美的暗魔法:VBScript。但如果让他具体写代码简单实现一下,直接懵了。

所以面试中一定要有写伪代码的流程,不然有可能招进来一个水货。

Object.defineProperty

先来看一段代码吧:

var o = {}, aValue = 2, bValue = 38;

Object.defineProperty(o, "a", {
  get: function() { return aValue; },
  set: function(newValue) { aValue = newValue; },
  enumerable: true,
  configurable: true
});

Object.defineProperty(o, "b", {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});

Object.defineProperty(o, "c", {
  get: function() { return this.a + this.b; },
  enumerable: true,
  configurable: true
});

上面实现的功能就是o.c = o.a + o.b。当a和b这两个属性变化时,c属性也会对应发生变化。

监听对象变化的简单实现

// 观察者构造函数
function Observer(data) {
    this.data = data;
    this.walk(data)
}

let p = Observer.prototype;

// 此函数用于深层次遍历对象的各个属性
// 采用的是递归的思路
// 因为我们要为对象的每一个属性绑定getter和setter
p.walk = function (obj) {
    let val;
    for (let key in obj) {
        // 这里为什么要用hasOwnProperty进行过滤呢?
        // 因为for...in 循环会把对象原型链上的所有可枚举属性都循环出来
        // 而我们想要的仅仅是这个对象本身拥有的属性,所以要这么做。
        if (obj.hasOwnProperty(key)) {
            val = obj[key];

            // 这里进行判断,如果还没有遍历到最底层,继续new Observer
            if (typeof val === "object") {
                new Observer(val);
            }

            this.convert(key, val);
        }
    }
};

p.convert = function (key, val) {
    Object.defineProperty(this.data, key, {
        enumerable: true,
        configurable: true,
        get: function () {
            console.log("你访问了" + key);
            return val
        },
        set: function (newVal) {
            console.log("你设置了" + key);
            console.log("新的" + key + " = " + newVal)
            if (newVal === val) return;
            val = newVal
        }
    })
};

let data = {
    user: {
        name: "liangshaofeng",
        age: "24"
    },
    address: {
        city: "beijing"
    }
};

let app = new Observer(data);

监听数组变化的简单实现

const aryMethods = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"];
const arrayAugmentations = [];

aryMethods.forEach((method)=> {

    // 这里是原生Array的原型方法
    let original = Array.prototype[method];

   // 将push, pop等封装好的方法定义在对象arrayAugmentations的属性上
   // 注意:是属性而非原型属性
    arrayAugmentations[method] = function () {
        console.log("我被改变啦!");

        // 调用对应的原生方法并返回结果
        return original.apply(this, arguments);
    };

});

let list = ["a", "b", "c"];
// 将我们要监听的数组的原型指针指向上面定义的空数组对象
// 别忘了这个空数组的属性上定义了我们封装好的push等方法
list.__proto__ = arrayAugmentations;
list.push("d");  // 我被改变啦! 4

// 这里的list2没有被重新定义原型指针,所以就正常输出
let list2 = ["a", "b", "c"];
list2.push("d");  // 4

另外的一种处理方式,使用es6里面的继承:

class FakeArray extends Array{
  push(...args){
      console.log("我被改变啦");
      return super.push(...args);
  }
}

var list = [1, 2, 3];

var arr = new FakeArray(...list);

console.log(arr.length)

arr.push(3);

console.log(arr)

(未完待续)

本文链接:www.my-fe.pub/post/to-achieve-mvvm.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。