defineProperty和Proxy

148 阅读2分钟

Object.defineProperty

function myDefineProperty() {
  var _obj = {};
  // Object.defineProperty(_obj,'a',{value:1})
  Object.defineProperties(_obj, {
    a: {
      value: 1,
      writable: true, //可修改
      enmuerable: true, //可枚举 遍历
      configurable: true, //可配置,删除
      //get: function () {}, //get set跟value writable互斥
      //set: function (newVal) {},
    },
  });
  return _obj;
}

var obj = myDefineProperty();

操作数组小例子

function DataArr() {
  var _val = null;
  var _arr = [];
  Object.defineProperty(this, "val", {
    get: function () {
      return _val;
    },
    set: function (newVal) {
      _val = newVal;
      _arr.push({ val: _val });
    },
  });
  this.getArr = function () {
    return _arr;
  };
}
var dataArr = new DataArr();

Proxy

其实就是 es6 里的一个构造函数

Proxy handler 重写 proxy 内部方法->转发给 target

而 defineProperty 劫持数据->给对象进行扩展->属性进行设置

defineProperty 数组 push 无法触发而 proxy 可以

var target = {
  a: 1,
  b: 2,
};

let proxy = new Proxy(target, {
  get(target, prop) {
    console.log(target[prop]);
  },
  set(target, prop, value) {
    target[prop] = value;
  },
});

手写 Proxy

function MyProxy(target, handler) {
  let _target = deepClone(target);
  console.log(_target);
  Object.keys(_target).forEach((key) => {
    Object.defineProperty(_target, key, {
      get() {
        return handler.get && handler.get(target, key);
      },
      set(newVal) {
        handler.set && handler.set(target, key, newVal);
      },
    });
  });
  return _target;

  function deepClone(target, newObj) {
    let tempObj = newObj || {};
    let toStr = Object.prototype.toString;
    let arrType = "[Object Array]";
    for (let key in target) {
      if (target.hasOwnProperty(key)) {
        if (typeof target[key] === "object" && target[key] !== null) {
          if (toStr.call(target[key]) === arrType) {
            tempObj[key] = [];
          } else {
            tempObj[key] = {};
          }
          deepClone(target[key], tempObj[key]);
        } else {
          tempObj[key] = target[key];
        }
      }
    }
    return tempObj;
  }
}

const obj = { a: 1, b: 3, c: [1, 2, { c: 1 }] };
const myproxy = new MyProxy(obj, {
  get(target, prop) {
    return target[prop];
  },
  set(target, prop, val) {
    target[prop] = val;
  },
});
myproxy.a = 3;
console.log(myproxy);

Object 内建 14 种方法

  • 获取原型[[GetPrototypeOf]]
    //暴露出的api是
    Object.getPrototypeOf(obj);
    obj.__proto__;
    Object.prototype;
    
  • 设置原型[[SetPrototypeOf]]
    //暴露出的api是
    Object.setPrototypeOf(obj, { a: 123 });
    Object.prototype.a = 123;
    
  • 获取对象的可扩展性[[IsExtensible]]
    //暴露出的api是
    Object.isExtensible(obj);
    
  • 获取自有属性[[GetOwnProperty]]
    //暴露出的api是
    Object.getOwnPropertyNames(obj);
    
  • 禁止扩展对象[[PreventExtensions]]
    //暴露出的api是
    Object.preventExtensions(obj);
    
  • 拦截对象操作[[DefineOwnProperty]]
    //暴露出的api是
    Object.defineProperty(obj, a, handler);
    
  • 判断是否为自身属性[[HasProperty]]
    //暴露出的api是
    obj.hasOwnPropety("a");
    
  • [[GET]]
    //暴露出的api是
    "a" in obj;
    obj.a;
    
  • [[SET]]
  • [[DELETE]]
  • 枚举[[Enumrate]]
    //暴露出的api是
    for (var key in obj) {
      console.log(obj[key]);
    }
    
  • 获取键集合[[OwnPropertyKeys]]
    //暴露出的api是
    Object.keys(obj);
    
  • 调用函数的方法
  • new 实例化操作