经过代理进行对象访问控制

对象属性的get、set

为了建立对象私有变量,咱们会在构造函数中经过定义的getter、setter函数闭包访问和修改私有属性。javascript

function Man() {
  let name = "liu";
  this.getName = () => {
    console.log("getname");
    return name;
  };
  this.setName = name => {
    console.log("setname");
    name = name;
  };
}
let man = new Man();
let name = man.getName();
console.log(name);
man.setName("zhang");
复制代码

使用get和set关键字在对象字面量中定义getter、setter。java

const Man = {
  _name: "liu",
  get name() {
    console.log("getname");
    return this._name;
  },
  set name(name) {
    console.log("setname");
    this._name = name;
  }
};
let name = Man.name;
console.log(name);
Man.name = "zhang";
console.log(Man._name);
复制代码

能够看出经过get和set关键字定义出的getter、setter更像是属性而不是方法。 使用get和set关键字在class中定义getter、setter,方法相似。数组

class Man {
  constructor() {
    this._name = "liu";
  }
  get name() {
    console.log("getname");
    return this._name;
  }
  set name(name) {
    console.log("setname");
    this._name = name;
  }
}
const man = new Man();
let name = man.name;
console.log(name);
man.name = "zhang";
console.log(man._name);
复制代码

回到第一个构造函数,咱们想改写它的getter、setter,能够像访问属性同样访问name私有属性,而get和set关键字只能在对象和class中定义,因此还须要借助于Object.defineProperty()方法,在传入的参数中定义getter、setter。闭包

function Man() {
  let _name = "liu";
  Object.defineProperty(this, "name", {
    get: () => {
      console.log("getname");
      return _name;
    },
    set: name => {
      console.log("setname");
      _name = name;
    }
  });
}
const man = new Man();
let name = man.name;
console.log(name);
man.name = "zhang";
console.log(man.name);
复制代码

Object.defineProperty中传入的参数this将指向man,并绑定传入的name属性,而name属性的特性由后面的对象配置。这其中就包含了经过get和set关键字定义出的getter、setter。当咱们访问和修改name属性时将调用get和set对应的函数。app

经过setter能够对传入值进行校验函数

function Man() {
  let _age = 20;
  Object.defineProperty(this, "age", {
    get: () => {
      console.log("getage");
      return _age;
    },
    set: age => {
      console.log("set_age");
      if (!Number.isInteger(age)) {
        throw new TypeError("age should be number!!");
      } else {
        _age = age;
      }
    }
  });
}
const man = new Man();
let age = man.age;
console.log(age);
man.age = 10;
console.log(man.age);
man.age = "zhang";
复制代码

当age为整数时能够成功赋值,若是是小数或其余数据类型将抛出错误提示性能

整个对象的get、set

以上能够看作对对象的某个属性进行代理操做,当咱们要对对象的每一个属性进行代理时,挨个属性代理将行不通,咱们须要使用Proxy构造函数对对象进行代理,代理操做最终将做用于源对象。测试

let man = { name: "liu" };
man = new Proxy(man, {
  get: (target, key) => {
    console.log("getProperty");
    return key in target ? target[key] : "Don't have";
  },
  set: (target, key, value) => {
    console.log("setProperty");
    target[key] = value;
    return true;
  }
});
let name = man.name;
console.log(name);
man.name = "zhang";
name = man.name;
console.log(name);
复制代码

以上代码经过Proxy构造函数建立出man对象的代理对象并从新赋值给man标识符(最初的man对象最为代理对象的目标对象将保持活跃,相似闭包),Proxy构造函数中传入需代理的man对象以及配置对象,配置对象中定义了每一个属性的getter、setter,须要注意set方法中咱们须要返回Boolean值,明确是否设置成功。ui

固然数组也是对象,因此Proxy也能够代理数组,咱们能够经过代理数组扩展原生数组功能,如JavaScript中数组索引不能为负数,经过代理数组能够解决。this

function array(array) {
  if (!Array.isArray(array)) {
    throw new TypeError("unexpected type !");
  }
  return new Proxy(array, {
    get: (target, index) => {
      console.log("get");
      index = +index;
      return target[index > 0 ? index : target.length + index];
    },
    set: (target, index, value) => {
      console.log("set");
      index = +index;
      return (target[index > 0 ? index : target.length + index] = value);
    }
  });
}
const mans = ["liu", "zhang", "li"];
let woman = "liu";
const man = array(mans);
console.log(man[-1]);
man[-1] = "wang";
console.log(mans);
复制代码

咱们在get和set方法中先将传入的索引index经过一元操做符“+”转换为数值,再经过判断index是否大于零决定索引index仍是target.length + index。

除了代理对象咱们也能够代理函数,当咱们须要测试函数性能时,可以使用代理函数计算执行时长。

function isPrime(number) {
  if (number < 2) {
    return false;
  }
  for (let i = 2; i < number; i++) {
    if (number % i === 0) {
      return false;
    }
  }
  return true;
}

isPrime = new Proxy(isPrime, {
  apply: (target, thisArg, argumentList) => {
    console.time("isPrime");
    const result = target.apply(thisArg, argumentList);
    console.timeEnd("isPrime");
    return result;
  }
});
console.log(isPrime(11373212));
复制代码

咱们先定义了用于计算传入的数字是否为素数的isPrime函数,以后经过Proxy构造函数传入isPrime函数获得新的isPrime代理函数,其中传入的配置对象设置了apply方法该方法在代理函数被执行时执行,该方法将默认传入目标函数、当前函数执行上下文以及参数列表,以后经过applay将当前函数执行上下文绑定到目标函数并传入参数执行。执行先后经过设置计时器(timer)打印执行时间。

相关文章
相关标签/搜索