JavaScript的es6新增Proxy/Reflect ,你知道吗?

之前学了vue3课程(vue3的响应式原理使用的就是Proxy),课程中老师经常提到proxy、响应式原理等,感觉很难很高深。现在学了,才真正了解。

一、Proxy类(代理)

        监听一个对象的相关操作,比如对象添加、删除、修改属性等。通过捕获器监听对象的改变。

        在es6直接如果想要监听对象的改变,需要使用Object.defineProperty()进行监听。代码如下:

1.Object.defineProperty()监听对象改变

const obj = {name:'wgy',age:18}
Object.defineProperty(obj,'name',{
    get:function(){
        console.log('name属性被访问了')
    },
    set:function(newVal){
        console.log('name属性被设置了',newVal)
    }
})
console.log(obj.name)
obj.name = 'kobo'

2.Object.defineProperty()的缺点

  • 比如新增属性、删除属性,defineProperty监听不到

  • defineProperty的设计初衷是定义普通的属性,不是为了去监听一个对象中的所有属性

3.Proxy监听对象改变

const obj = { name: "wgy", age: 18 };

const objProxy = new Proxy(obj, {
  // 获取值时的捕获器  target-obj,key-name
  get(target, key, receiver) {
    console.log("值被获取了", target, key);
    return target[key];
  },
  // 设置值时的捕获器
  set(target, key, newValue, receiver) {
    console.log("值被设置了", newValue);
    target[key] = newValue;
  },
  // 监听in的捕获器
  has(target, key) {
    console.log("对象执行了in操作");
    return key in target;
  },
  // 监听delete的捕获器
  deleteProperty(target, key) {
    console.log("对象执行了delete操作");
    delete target[key];
  },
});

console.log(objProxy.name);
objProxy.name = "3333";
console.log(obj);
console.log("name" in objProxy);
delete objProxy.name;

  4. 其他捕获器

  • getPrototype()

    • Object.getPrototypeof() 获取对象的原型

  • setPrototype()

    • Object.setPrototypeof() 设置对象的原型

  • isExtensible()

    • Object.isExtensible() 判断对象是否可以添加属性

  • preventExtensions()

    • Object.preventExtensions() 阻止对象添加属性

  • getOwnPrototyDescriptor()

    • Object.getOwnPrototyDescriptor() 获取对象的属性描述符

  • defineProperty()

    • Object.defineProperty() 给对象添加属性描述符

  • ownKeys()

    • Object.getOwnPrototyNames()

    • Object.getOwnPrototySymbols()

  • apply() 用于函数对象

    • 监听函数调用操作

  • construct 用于函数对象

    • 监听new 操作符

//apply()和construct()捕获器用于函数对象,使用方法
function foo() {
  console.log(foo);
}
const fooProxy = new Proxy(foo, {
  apply(target, thisAry, argArray) {
    console.log("函数被调用了", thisAry, argArray);
    target.apply(thisAry, argArray);
  },
  construct(target, argArray, newTarget) {
    console.log("函数使用new");
    return new target(...argArray);
  },
});
fooProxy();
fooProxy.apply({}, [1, 4, 6]);
new fooProxy();

5.Proxy的receiver参数的使用

      修改this指向,是代理有意义。

const obj = {
  _name: "www",
  get name() {
    console.log(this);
    return this._name; //this指向obj
  },
  set name(newVal) {
    this._name = newVal;
  },
};

const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    // receiver是代理对象objProxy
    console.log("属性被获取了", key, receiver === objProxy);
    return Reflect.get(target, key, receiver);
    // 传入receiver,会把this改为代理对象receiver
  },
  set(target, key, newVal, receiver) {
    console.log("属性被设置了");
    Reflect.set(target, key, newVal, receiver);
  },
});

console.log(objProxy.name); //访问的是obj的get name
objProxy.name = "333333";

二、Reflect对象(映射)

     Reflect对象提供了很多操作js对象的方法,比如增删改等。与Object提供的方法类似。

     一般与Proxy配合使用。

const obj = { name: "www", age: 22 };

const objProxy = new Proxy(obj, {
  get(target, key) {
    // return target[key]
    return Reflect.get(target, key);
  },
  set(target, key, newValue) {
    // target[key] = newValue;
    let res = Reflect.set(target, key, newValue);
    console.log(res);//会返回设置结果
  },
});

console.log(objProxy);
objProxy.name = "hhh";

1.为什么会需要Reflect

  • 早期的ECMA规范中没有考虑到对对象本地操作如何设计会更规范,所以将这些方法API放到了Object上

  • Object作为一个构造函数,这些放到他身上不合适

  • 还包含一下类似于in、delete操作符,让js看起来有点奇怪

2.与Object方法的区别

可参考比较 Reflect 和 Object 方法 - JavaScript | MDN

3.Reflect的方法

  • Reflect.apply()

    • 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。

  • Reflect.construct(target, argumentsList[, newTarget])

    • 对构造函数进行new操作

  • Reflect.defineProperty(target, propertyKey, attributes)

    • Object.defineProperty()

  • Reflect.deleteProperty(target, propertyKey)

    • Object.preventExtensions() 阻止对象添加属性

  • Reflect.get(target, propertyKey[, receiver])

    •  获取对象的属性

  • Reflect.getOwnPropertyDescriptor(target, propertyKey)

    • Object.getOwnPropertyDescriptor()

  • Reflect.getPrototypeOf(target)

    • Object.getPrototypeOf()

  • Reflect.has(target, propertyKey)

    • Object.isExtensible()

  • Reflect.ownKeys(target)

    • Object.keys()

  •  Reflect.preventExtensions(target)

    •  Object.preventExtensions()

  •  Reflect.set(target, propertyKey, value[, receiver])

    •  设置对象属性

  •  Reflect.setPrototypeOf(target, prototype)

    •  设置对象的原型

4.Reflect.construct()的使用

const stu = new Student("ww", 32);
console.log(stu);
console.log(stu.__proto__ === Student.prototype);

// 执行Student函数,创建出来的对象是Teacher对象
const tea = Reflect.construct(Student, ["wwww", 22], Teacher);
console.log(tea);
console.log(tea.__proto__ === Teacher.prototype);

参考:Reflect - JavaScript | MDN 

参考:深入JavaScript高级语法-coderwhy大神新课-学习视频教程-腾讯课堂

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值