從ES6的Proxy代理看ES5的代理如何實現

從ES6的Proxy代理看ES5的代理如何實現

ES6的Proxy代理

Examplevue

var person = {name:''};
var personCopy = new Proxy(person,{
  get(target,key,receiver){
    console.log('get方法被攔截。。。');
    return Reflect.get(target,key,receiver);
  },
  set(target,key,value,receiver){
    console.log('set方法被攔截。。。')
    return Reflect.set(target,key,value,receiver);
  }
})
person.name = 'arvin';  // 未有攔截日誌打出
personCopy.name = 'arvin';  // set方法被攔截。。。
console.log(person.name);   // 未有攔截日誌打出
console.log(personCopy.name);   // get方法被攔截。。。

代碼解讀:從上述的例子能夠看出,被代理對象person的get和set不會通過代理攔截器get,set,而只有代理對象personCopy在get和set方法調用的時候纔會通過攔截器,因而可知ES6的代理Proxy並非一個相似JAVA的AOP,而其實只是將person的引用賦值給了personCopy,讓代理對象personCopy和被代理對象person指向了同一個內存空間,下面是我實現的一個用ES5寫的Proxy攔截,供你們參考理解Proxy實現原理提供思路:工具

Example:this

/**淺拷貝工具方法**/
function clone(myObj){  
    if(typeof(myObj) != 'object' || myObj == null) return myObj;  
    var newObj = new Object();  
    for(var i in myObj){  
      newObj[i] = clone(myObj[i]); 
    }  
    return newObj;  
}
/*代理實現類*/
function ProxyCopy(target,handle){
  var targetCopy = clone(target);
  Object.keys(targetCopy).forEach(function(key){
    Object.defineProperty(targetCopy, key, {
      get: function() {
        return handle.get && handle.get(target,key);
      },
      set: function(newVal) {
        handle.set && handle.set();
        target[key] = newVal;
      }
    });
  })
  return targetCopy;
}

var person = {name:''};
var personCopy = new ProxyCopy(person,{
  get(target,key){
    console.log('get方法被攔截。。。');
    return target[key];
  },
  set(target,key,value){
    console.log('set方法被攔截。。。')
    // return true;
  }
})
person.name = 'arvin';  // 未有攔截日誌打出
personCopy.name = 'arvin';  // set方法被攔截。。。
console.log(person.name);   // 未有攔截日誌打出
console.log(personCopy.name);   // get方法被攔截。。。

ES5對Proxy代理的實現

要說到ES5的代理實現,其中比較有名的就算是vue的雙向綁定中到了get和set的代理攔截實現了,下面是一個仿照該技術的一個實現:prototype

Example雙向綁定

// 攔截器
function Observer(data) {
    this.data = data;
    this.walk(data);
}
(function($Observer){
    $Observer.prototype = {
        walk: function(data) {
            var me = this;
            Object.keys(data).forEach(function(key) {
                me.convert(key, data[key]);
            });
        },
        convert: function(key, val) {
            this.defineReactive(this.data, key, val);
        },
        defineReactive: function(data, key, val) {
            var childObj = observe(val);
            Object.defineProperty(data, key, {
                enumerable: true, // 可枚舉
                configurable: false, // 不能再define
                get: function() {
                    return val;
                },
                set: function(newVal) {
                    if (newVal === val) {
                        return;
                    }
                    val = newVal;
                    console.log("新的值是object的話,進行監聽");
                    console.log("通知訂閱者");
                    dep.notify();
                }
            });
        }
};
})(Observer);
// 攔截器的出口
function observe(value) {
    if (!value || typeof value !== 'object') {
        return;
    }
    return new Observer(value);
};
相關文章
相關標籤/搜索