Skip to content
On this page

代理与反射

属性描述符

Property Descriptor

Property Descriptor 属性描述符 是一个普通对象,用于描述一个属性的相关信息 通过Object.getOwnPropertyDescriptor(对象, 属性名)可以得到一个对象的某个属性的属性描述符

javascript
const desc = Object.getOwnPropertyDescriptor(obj, "a");
console.log(desc);
const desc = Object.getOwnPropertyDescriptor(obj, "a");
console.log(desc);
  • value:属性值
  • configurable:该属性的描述符是否可以修改
  • enumerable:该属性是否可以被枚举
  • writable:该属性是否可以被重新赋值

    Object.getOwnPropertyDescriptors(对象)可以得到某个对象的所有属性描述符

如果需要为某个对象添加属性时 或 修改属性时, 配置其属性描述符,可以使用下面的代码: Object.defineProperty(对象, 属性名, 描述符);

javascript
const obj = {
  a: 1,
  b: 2,
};
Object.defineProperty(obj, "a", {
  value: 3,
  configurable: false, //描述符不可以修改
  enumerable: false, //不可枚举
  writable: false, //不可写
});
console.log(obj);
for (const prop in obj) {
  console.log(prop); //只有b,没有a了
}
obj.a = 10; //不可写
console.log(obj);
const props = Object.keys(obj); //得到对象的所有属性
console.log(props);
const values = Object.values(obj); //得到对象的所有值
console.log(values);
const obj = {
  a: 1,
  b: 2,
};
Object.defineProperty(obj, "a", {
  value: 3,
  configurable: false, //描述符不可以修改
  enumerable: false, //不可枚举
  writable: false, //不可写
});
console.log(obj);
for (const prop in obj) {
  console.log(prop); //只有b,没有a了
}
obj.a = 10; //不可写
console.log(obj);
const props = Object.keys(obj); //得到对象的所有属性
console.log(props);
const values = Object.values(obj); //得到对象的所有值
console.log(values);

Object.defineProperties(对象, 多个属性的描述符)

javascript
Object.defineProperties(obj, {
  a: {
    value: 3,
    configurable: false,
    enumerable: false,
    writable: false,
  },
});
Object.defineProperties(obj, {
  a: {
    value: 3,
    configurable: false,
    enumerable: false,
    writable: false,
  },
});

存取器属性

属性描述符中,如果配置了 get 和 set 中的任何一个,则该属性,不再是一个普通属性,而变成了存取器属性。 get 和 set 配置均为函数,如果一个属性是存取器属性,则读取该属性时,会运行 get 方法,将 get 方法得到的返回值作为属性值;如果给该属性赋值,则会运行 set 方法。 属性已经不再内存里面了,而是 get 和 set

javascript
const obj = {
  b: 2,
};
Object.defineProperty(obj, "a", {
  get() {
    console.log("运行了属性a的get函数");
  },
  set(val) {
    console.log("运行了属性a的set函数", val);
  },
});
// obj.a的时候运行get函数
// obj.a赋值的时候运行set函数
// 所以console.log(obj.a)//undefined,因为get函数没有返回结果
obj.a = 1; //相当于set(20)
console.log(obj.a); // 相当于console.log(get())
// 运行set
// 运行get
// undefined
const obj = {
  b: 2,
};
Object.defineProperty(obj, "a", {
  get() {
    console.log("运行了属性a的get函数");
  },
  set(val) {
    console.log("运行了属性a的set函数", val);
  },
});
// obj.a的时候运行get函数
// obj.a赋值的时候运行set函数
// 所以console.log(obj.a)//undefined,因为get函数没有返回结果
obj.a = 1; //相当于set(20)
console.log(obj.a); // 相当于console.log(get())
// 运行set
// 运行get
// undefined
javascript
// 演示1
obj.a = 20 + 10; // set(20 + 10) 相当于运行set()
console.log(obj.a); // console.log(get()) 读取属性a,相当于运行get()
// 演示2
obj.a = obj.a + 1; // set(obj.a + 1) 相当于读取 set(get() + 1)  undefined+1=NaN
console.log(obj.a); //读取属性一定运行get  undefined
// 演示1
obj.a = 20 + 10; // set(20 + 10) 相当于运行set()
console.log(obj.a); // console.log(get()) 读取属性a,相当于运行get()
// 演示2
obj.a = obj.a + 1; // set(obj.a + 1) 相当于读取 set(get() + 1)  undefined+1=NaN
console.log(obj.a); //读取属性一定运行get  undefined
javascript
const obj = {
  b: 2,
};
Object.defineProperty(obj, "a", {
  get() {
    console.log("运行了属性a的get函数");
    return obj._a;
    // 错误的思路:return obj.a
    // 这里就成了无限递归,无限读取,导致浏览器卡死,同理set
  },
  set(val) {
    console.log("运行了属性a的set函数", val);
    obj._a = val;
  },
});
obj.a = 10;
console.log(obj.a);
const obj = {
  b: 2,
};
Object.defineProperty(obj, "a", {
  get() {
    console.log("运行了属性a的get函数");
    return obj._a;
    // 错误的思路:return obj.a
    // 这里就成了无限递归,无限读取,导致浏览器卡死,同理set
  },
  set(val) {
    console.log("运行了属性a的set函数", val);
    obj._a = val;
  },
});
obj.a = 10;
console.log(obj.a);

存取器属性最大的意义,在于可以控制属性的读取和赋值

javascript
obj = {
  name: "adsf",
};
Object.defineProperty(obj, "age", {
  get() {
    return obj._age;
  },
  set(val) {
    if (typeof val !== "number") {
      throw new TypeError("年龄必须是一个数字");
    }
    if (val < 0) {
      val = 0;
    } else if (val > 200) {
      val = 200;
    }
    obj._age = val;
  },
});
obj.age = "Asdfasasdf";
console.log(obj.age);
obj = {
  name: "adsf",
};
Object.defineProperty(obj, "age", {
  get() {
    return obj._age;
  },
  set(val) {
    if (typeof val !== "number") {
      throw new TypeError("年龄必须是一个数字");
    }
    if (val < 0) {
      val = 0;
    } else if (val > 200) {
      val = 200;
    }
    obj._age = val;
  },
});
obj.age = "Asdfasasdf";
console.log(obj.age);

应用:将对象的属性和元素关联

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    <p>
      <span>姓名:</span>
      <span id="name"></span>
    </p>
    <p>
      <span>年龄:</span>
      <span id="age"></span>
    </p>
    <script>
      const spanName = document.getElementById("name");
      const spanAge = document.getElementById("age");
      const user = {};
      Object.defineProperties(user, {
        name: {
          get() {
            return spanName.innerText;
            //获取页面窗口中对应的元素内容
          },
          set(val) {
            spanName.innerText = val;
          },
        },
        age: {
          get() {
            return +spanAge.innerText;
          },
          set(val) {
            if (typeof val !== "number") {
              throw new TypeError("年龄必须是一个数字");
            }
            if (val < 0) {
              val = 0;
            } else if (val > 200) {
              val = 200;
            }
            spanAge.innerText = val;
          },
        },
      });
    </script>
  </body>
</html>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    <p>
      <span>姓名:</span>
      <span id="name"></span>
    </p>
    <p>
      <span>年龄:</span>
      <span id="age"></span>
    </p>
    <script>
      const spanName = document.getElementById("name");
      const spanAge = document.getElementById("age");
      const user = {};
      Object.defineProperties(user, {
        name: {
          get() {
            return spanName.innerText;
            //获取页面窗口中对应的元素内容
          },
          set(val) {
            spanName.innerText = val;
          },
        },
        age: {
          get() {
            return +spanAge.innerText;
          },
          set(val) {
            if (typeof val !== "number") {
              throw new TypeError("年龄必须是一个数字");
            }
            if (val < 0) {
              val = 0;
            } else if (val > 200) {
              val = 200;
            }
            spanAge.innerText = val;
          },
        },
      });
    </script>
  </body>
</html>

属性描述符应用

js
var obj = {
  b: 2,
};

// 得到属性描述符
// var desc = Object.getOwnPropertyDescriptor(obj, 'a');
// console.log(desc);

// 设置属性描述符
Object.defineProperty(obj, "a", {
  value: 10,
  writable: false, // 不可重写
  enumerable: false, // 不可遍历
  configurable: false, // 不可修改描述符本身
});
// Object.defineProperty(obj, 'a', {
//   writable: true,
// });
obj.a = "abc";
console.log(obj.a);
// for (var key in obj) {
//   console.log(key);
// }

// var keys = Object.keys(obj);
// console.log(keys);

// console.log(obj);
var obj = {
  b: 2,
};

// 得到属性描述符
// var desc = Object.getOwnPropertyDescriptor(obj, 'a');
// console.log(desc);

// 设置属性描述符
Object.defineProperty(obj, "a", {
  value: 10,
  writable: false, // 不可重写
  enumerable: false, // 不可遍历
  configurable: false, // 不可修改描述符本身
});
// Object.defineProperty(obj, 'a', {
//   writable: true,
// });
obj.a = "abc";
console.log(obj.a);
// for (var key in obj) {
//   console.log(key);
// }

// var keys = Object.keys(obj);
// console.log(keys);

// console.log(obj);
js
var obj = {};

Object.defineProperty(obj, "a", {
  get: function () {
    return 123;
  }, // 读取器 getter
  set: function (val) {
    throw new Error(
      `兄弟,你正在给a这个属性重新赋值,你所赋的值是${val},但是,这个属性是不能复制,你再考虑考虑`
    );
  }, // 设置器 setter
});

console.log(obj.a);
obj.a = "abx";
// console.log(obj.a); // console.log(get())
var obj = {};

Object.defineProperty(obj, "a", {
  get: function () {
    return 123;
  }, // 读取器 getter
  set: function (val) {
    throw new Error(
      `兄弟,你正在给a这个属性重新赋值,你所赋的值是${val},但是,这个属性是不能复制,你再考虑考虑`
    );
  }, // 设置器 setter
});

console.log(obj.a);
obj.a = "abx";
// console.log(obj.a); // console.log(get())

购物车描述

js
var aGoods = {
  pic: ".",
  title: "..",
  desc: `...`,
  sellNumber: 1,
  favorRate: 2,
  price: 3,
};

class UIGoods {
  get totalPrice() {
    return this.choose * this.data.price;
  }

  get isChoose() {
    return this.choose > 0;
  }

  constructor(g) {
    g = { ...g }; // 克隆一份
    Object.freeze(g); // 冻结克隆对象
    Object.defineProperty(this, "data", {
      get: function () {
        return g;
      },
      set: function () {
        throw new Error("data 属性是只读的,不能重新赋值");
      },
      configurable: false,
    });
    var internalChooseValue = 0;
    Object.defineProperty(this, "choose", {
      configurable: false,
      get: function () {
        return internalChooseValue;
      },
      set: function (val) {
        if (typeof val !== "number") {
          throw new Error("choose属性必须是数字");
        }
        var temp = parseInt(val);
        if (temp !== val) {
          throw new Error("choose属性必须是整数");
        }
        if (val < 0) {
          throw new Error("choose属性必须大于等于 0");
        }
        internalChooseValue = val;
      },
    });
    this.a = 1;
    Object.seal(this); // 密封自己 不能加属性了,其他属性还可以改
  }
}

Object.freeze(UIGoods.prototype);

var g = new UIGoods(aGoods);

UIGoods.prototype.haha = "abc";
// g.data.price = 100;

console.log(g.haha);

// 思考:能不能想到各种场景,提前预防
var aGoods = {
  pic: ".",
  title: "..",
  desc: `...`,
  sellNumber: 1,
  favorRate: 2,
  price: 3,
};

class UIGoods {
  get totalPrice() {
    return this.choose * this.data.price;
  }

  get isChoose() {
    return this.choose > 0;
  }

  constructor(g) {
    g = { ...g }; // 克隆一份
    Object.freeze(g); // 冻结克隆对象
    Object.defineProperty(this, "data", {
      get: function () {
        return g;
      },
      set: function () {
        throw new Error("data 属性是只读的,不能重新赋值");
      },
      configurable: false,
    });
    var internalChooseValue = 0;
    Object.defineProperty(this, "choose", {
      configurable: false,
      get: function () {
        return internalChooseValue;
      },
      set: function (val) {
        if (typeof val !== "number") {
          throw new Error("choose属性必须是数字");
        }
        var temp = parseInt(val);
        if (temp !== val) {
          throw new Error("choose属性必须是整数");
        }
        if (val < 0) {
          throw new Error("choose属性必须大于等于 0");
        }
        internalChooseValue = val;
      },
    });
    this.a = 1;
    Object.seal(this); // 密封自己 不能加属性了,其他属性还可以改
  }
}

Object.freeze(UIGoods.prototype);

var g = new UIGoods(aGoods);

UIGoods.prototype.haha = "abc";
// g.data.price = 100;

console.log(g.haha);

// 思考:能不能想到各种场景,提前预防

Reflect

Reflect 是什么?

Reflect 是一个内置的 JS 对象,它提供了一系列方法,可以让开发者通过调用这些方法,访问一些 JS 底层功能 由于它类似于其他语言的反射,因此取名为 Reflect

它可以做什么?

使用 Reflect 可以实现诸如 属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在与对象中   等等功能

这些功能不是已经存在了吗?为什么还需要用 Reflect 实现一次?

有一个重要的理念,在 ES5 就被提出:减少魔法、让代码更加纯粹,这种理念很大程度上是受到函数式编程的影响

ES6 进一步贯彻了这种理念,它认为,对属性内存的控制、原型链的修改、函数的调用等等,这些都属于底层实现,属于一种魔法,因此,需要将它们提取出来,形成一个正常的 API,并高度聚合到某个对象中,于是,就造就了 Reflect 对象

因此,你可以看到 Reflect 对象中有很多的 API 都可以使用过去的某种语法或其他 API 实现。

它里面到底提供了哪些 API 呢?

  • Reflect.set(target, propertyKey, value): 设置对象 target 的属性 propertyKey 的值为 value,等同于给对象的属性赋值
javascript
const obj = {
  a: 1,
  b: 2,
};
// obj.a = 10;
Reflect.set(obj, "a", 10); //给obj的a赋值为10
console.log(Reflect.get(obj, "a"));
const obj = {
  a: 1,
  b: 2,
};
// obj.a = 10;
Reflect.set(obj, "a", 10); //给obj的a赋值为10
console.log(Reflect.get(obj, "a"));
  • Reflect.get(target, propertyKey): 读取对象 target 的属性 propertyKey,等同于读取对象的属性值
  • Reflect.apply(target, thisArgument, argumentsList):调用一个指定的函数,并绑定 this 和参数列表。等同于函数调用
  • Reflect.deleteProperty(target, propertyKey):删除一个对象的属性
  • Reflect.defineProperty(target, propertyKey, attributes):类似于 Object.defineProperty,不同的是如果配置出现问题,返回 false 而不是报错
  • Reflect.construct(target, argumentsList):用构造函数的方式创建一个对象
  • Reflect.has(target, propertyKey): 判断一个对象是否拥有一个属性
  • 其他 API
javascript
function method(a, b) {
  console.log("method", a, b);
}
// method(3, 4);
Reflect.apply(method, null, [3, 4]);

const obj = {
  a: 1,
  b: 2,
};
// delete obj.a;
Reflect.deleteProperty(obj, "a");
console.log(obj);

function Test(a, b) {
  this.a = a;
  this.b = b;
}

// const t = new Test(1, 3);
const t = Reflect.construct(Test, [1, 3]);
console.log(t);
function method(a, b) {
  console.log("method", a, b);
}
// method(3, 4);
Reflect.apply(method, null, [3, 4]);

const obj = {
  a: 1,
  b: 2,
};
// delete obj.a;
Reflect.deleteProperty(obj, "a");
console.log(obj);

function Test(a, b) {
  this.a = a;
  this.b = b;
}

// const t = new Test(1, 3);
const t = Reflect.construct(Test, [1, 3]);
console.log(t);
js
const obj = {
  a: 1,
  b: 2,
};

// console.log("a" in obj);
console.log(Reflect.has(obj, "a"));
const obj = {
  a: 1,
  b: 2,
};

// console.log("a" in obj);
console.log(Reflect.has(obj, "a"));

Proxy

提供了修改底层实现的方式

javascript
//代理一个目标对象
//target:目标对象
//handler:是一个普通对象,其中可以重写底层实现(可以重写反射里面所有的api)
//返回一个代理对象
new Proxy(target, handler);
//代理一个目标对象
//target:目标对象
//handler:是一个普通对象,其中可以重写底层实现(可以重写反射里面所有的api)
//返回一个代理对象
new Proxy(target, handler);
javascript
const obj = {
  a: 1,
  b: 2,
};

const proxy = new Proxy(obj, {
  set(target, propertyKey, value) {
    // console.log(target, propertyKey, value);
    // target[propertyKey] = value;修改属性的值。重写了底层实现

    // 等价于
    Reflect.set(target, propertyKey, value);
  },
  get(target, propertyKey) {
    if (Reflect.has(target, propertyKey)) {
      return Reflect.get(target, propertyKey);
    } else {
      return -1;
    }
  },
  has(target, propertyKey) {
    return false; //代理说没有就没有
  },
});
// console.log(proxy);
// proxy.a = 10;
// console.log(proxy.a);

console.log(proxy.d); //运行get
console.log("a" in proxy);
const obj = {
  a: 1,
  b: 2,
};

const proxy = new Proxy(obj, {
  set(target, propertyKey, value) {
    // console.log(target, propertyKey, value);
    // target[propertyKey] = value;修改属性的值。重写了底层实现

    // 等价于
    Reflect.set(target, propertyKey, value);
  },
  get(target, propertyKey) {
    if (Reflect.has(target, propertyKey)) {
      return Reflect.get(target, propertyKey);
    } else {
      return -1;
    }
  },
  has(target, propertyKey) {
    return false; //代理说没有就没有
  },
});
// console.log(proxy);
// proxy.a = 10;
// console.log(proxy.a);

console.log(proxy.d); //运行get
console.log("a" in proxy);

应用

观察者模式

有一个对象,是观察者,它用于观察另外一个对象的属性值变化,当属性值变化后会收到一个通知,可能会做一些事。

vue2

html
<div id="container"></div>
<script>
  //创建一个观察者
  function observer(target) {
    //通过观察目标元素的变化,把这些属性渲染到页面上
    const div = document.getElementById("container");
    const ob = {};
    const props = Object.keys(target); // 拿到所有属性名
    for (const prop of props) {
      Object.defineProperty(ob, prop, {
        get() {
          // 获取的时候
          return target[prop];
        },
        set(val) {
          // 设置的时候
          target[prop] = val;
          render();
        },
        enumerable: true, //这两个属性默认不能被枚举
      });
    }
    render();
    function render() {
      let html = "";
      for (const prop of Object.keys(ob)) {
        //拼接属性名属性值
        html += `
<p><span>${prop}:</span><span>${ob[prop]}</span></p>
`;
      }
      div.innerHTML = html;
    }
    return ob;
  }
  const target = {
    a: 1,
    b: 2,
  };
  const obj = observer(target);
</script>
<div id="container"></div>
<script>
  //创建一个观察者
  function observer(target) {
    //通过观察目标元素的变化,把这些属性渲染到页面上
    const div = document.getElementById("container");
    const ob = {};
    const props = Object.keys(target); // 拿到所有属性名
    for (const prop of props) {
      Object.defineProperty(ob, prop, {
        get() {
          // 获取的时候
          return target[prop];
        },
        set(val) {
          // 设置的时候
          target[prop] = val;
          render();
        },
        enumerable: true, //这两个属性默认不能被枚举
      });
    }
    render();
    function render() {
      let html = "";
      for (const prop of Object.keys(ob)) {
        //拼接属性名属性值
        html += `
<p><span>${prop}:</span><span>${ob[prop]}</span></p>
`;
      }
      div.innerHTML = html;
    }
    return ob;
  }
  const target = {
    a: 1,
    b: 2,
  };
  const obj = observer(target);
</script>

缺陷:搞出来了两个对象,占用了内存,代理不占用内存

vue3

html
<div id="container"></div>

<script>
  //创建一个观察者
  function observer(target) {
    const div = document.getElementById("container");
    const proxy = new Proxy(target, {
      set(target, prop, value) {
        // 重写底层实现
        Reflect.set(target, prop, value);
        render();
      },
      get(target, prop) {
        return Reflect.get(target, prop);
      },
    });
    render();
    function render() {
      let html = "";
      for (const prop of Object.keys(target)) {
        html += `
<p><span>${prop}:</span><span>${target[prop]}</span></p>
`;
      }
      div.innerHTML = html;
    }
    return proxy;
  }
  const target = {
    a: 1,
    b: 2,
  };
  const obj = observer(target);
</script>
<div id="container"></div>

<script>
  //创建一个观察者
  function observer(target) {
    const div = document.getElementById("container");
    const proxy = new Proxy(target, {
      set(target, prop, value) {
        // 重写底层实现
        Reflect.set(target, prop, value);
        render();
      },
      get(target, prop) {
        return Reflect.get(target, prop);
      },
    });
    render();
    function render() {
      let html = "";
      for (const prop of Object.keys(target)) {
        html += `
<p><span>${prop}:</span><span>${target[prop]}</span></p>
`;
      }
      div.innerHTML = html;
    }
    return proxy;
  }
  const target = {
    a: 1,
    b: 2,
  };
  const obj = observer(target);
</script>

偷懒的构造函数

恶心的类创建

javascript
class User(){
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
}
class User(){
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
}

自动赋值

javascript
class User {}
function ConstructorProxy(Class, ...propNames) {
  return new Proxy(Class, {
    construct(target, argumentsList) {
      const obj = Reflect.construct(target, argumentsList);
      propNames.forEach((name, i) => {
        obj[name] = argumentsList[i];
      });
      return obj;
    },
  });
}
const UserProxy = ConstructorProxy(User, "firstName", "lastName", "age");
const obj = new UserProxy("付", "志强", 18);
console.log(obj);
class Monster {}
const MonsterProxy = ConstructorProxy(
  Monster,
  "attack",
  "defence",
  "hp",
  "rate",
  "name"
);
const m = new MonsterProxy(10, 20, 100, 30, "怪物");
console.log(m);
class User {}
function ConstructorProxy(Class, ...propNames) {
  return new Proxy(Class, {
    construct(target, argumentsList) {
      const obj = Reflect.construct(target, argumentsList);
      propNames.forEach((name, i) => {
        obj[name] = argumentsList[i];
      });
      return obj;
    },
  });
}
const UserProxy = ConstructorProxy(User, "firstName", "lastName", "age");
const obj = new UserProxy("付", "志强", 18);
console.log(obj);
class Monster {}
const MonsterProxy = ConstructorProxy(
  Monster,
  "attack",
  "defence",
  "hp",
  "rate",
  "name"
);
const m = new MonsterProxy(10, 20, 100, 30, "怪物");
console.log(m);

可验证的函数参数

javascript
function sum(a, b) {
  return a + b;
}

function validatorFunction(func, ...types) {
  //并不占据内存空间,只是个代理
  const proxy = new Proxy(func, {
    apply(target, thisArgument, argumentsList) {
      types.forEach((t, i) => {
        // 进行验证
        const arg = argumentsList[i];
        if (typeof arg !== t) {
          throw new TypeError(
            `第${i + 1}个参数${argumentsList[i]}不满足类型${t}`
          );
        }
      });
      return Reflect.apply(target, thisArgument, argumentsList);
    },
  });
  return proxy;
}

const sumProxy = validatorFunction(sum, "number", "number");
console.log(sumProxy(1, 2));
function sum(a, b) {
  return a + b;
}

function validatorFunction(func, ...types) {
  //并不占据内存空间,只是个代理
  const proxy = new Proxy(func, {
    apply(target, thisArgument, argumentsList) {
      types.forEach((t, i) => {
        // 进行验证
        const arg = argumentsList[i];
        if (typeof arg !== t) {
          throw new TypeError(
            `第${i + 1}个参数${argumentsList[i]}不满足类型${t}`
          );
        }
      });
      return Reflect.apply(target, thisArgument, argumentsList);
    },
  });
  return proxy;
}

const sumProxy = validatorFunction(sum, "number", "number");
console.log(sumProxy(1, 2));

Proxy:如果没有我

javascript
function sum(a, b) {
  return a + b;
}

function validatorFunction(func, ...types) {
  return function (...argumentsList) {
    // 新的函数占用内存
    types.forEach((t, i) => {
      const arg = argumentsList[i];
      if (typeof arg !== t) {
        throw new TypeError(
          `第${i + 1}个参数${argumentsList[i]}不满足类型${t}`
        );
      }
    });
    return func(...argumentsList); //运行这个函数
  };
  return proxy;
}

const sumProxy = validatorFunction(sum, "number", "number");
console.log(sumProxy(1, 2));
function sum(a, b) {
  return a + b;
}

function validatorFunction(func, ...types) {
  return function (...argumentsList) {
    // 新的函数占用内存
    types.forEach((t, i) => {
      const arg = argumentsList[i];
      if (typeof arg !== t) {
        throw new TypeError(
          `第${i + 1}个参数${argumentsList[i]}不满足类型${t}`
        );
      }
    });
    return func(...argumentsList); //运行这个函数
  };
  return proxy;
}

const sumProxy = validatorFunction(sum, "number", "number");
console.log(sumProxy(1, 2));

其他 proxy 资料:

https://cloud.tencent.com/developer/article/1890562

https://juejin.cn/post/6844904101218631694