美文网首页
Proxy(代理)

Proxy(代理)

作者: 我家有个王胖胖 | 来源:发表于2022-03-09 21:54 被阅读0次

ES5:Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。
详细讲解
基本用法:

Object.defineProperty(obj, prop, desc)

参数说明:

  • obj 需要定义属性的当前对象
  • prop 当前需要定义的属性名
  • desc 属性描述符
    通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,分别为数据描述符,存取描述符。
    数据描述符:
    writeable:是否可以修改
 let person = {}
Object.defineProperty(person,'name',{
    value:'张三',
    writeable:false//默认为false,默认可省略
})
person.name = '李四'
console.log(person.name);//张三
let person = {}
Object.defineProperty(person,'name',{
    value:'张三',
    writeable:true//默认为false,默认可省略
})
person.name = '李四'
console.log(person.name);//李四

存取描述符:
get:一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
set:一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined。

let person = {}
let temp = null;//给他赋值,防止set方法陷入死循环
Object.defineProperty(person,name,{
    get: function() {
        return temp;
    },
    set: function(val) { 
        temp = val;
    }
})
person.name = '张三';
console.log(person.name);

注意

数据描述符和存取描述均具有以下描述符
configrable 能否使用delete、能否需改属性特性、或能否修改访问器属性
enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中

        let person = {};
        Object.defineProperty(person, 'name', {
                value: '张三',
                writable: true,
                configurable: false

            })
            //person.name = '李四';
        Object.defineProperty(person, 'name', {
            value: '李四',
        })
        console.log(person.name); //Cannot redefine property: name
let person = {
        name: "张三",
      };
      Object.defineProperty(person, "name", {
        configurable: false,
        enumerable: true,
        writable: false,
      });
      delete p.name;//"TypeError: Cannot delete property 'name' of #<Object>"

configrable:true 通过属性定义的方式可以被修改

let person = {};
        Object.defineProperty(person, 'name', {
            value: '张三',
            configrable: true,
            writable: true,
            enumerable: true

        })
        Object.defineProperty(person, 'name', {
            value: 'lisi',
        })
        console.log(person);//lisi
        delete person.name 
        console.log(person);//undefine

<meta charset="utf-8">

enumerable:


enumerable.png 默认属性值.png

对象常量
结合writable: false 和 configurable: false 就可以创建一个真正的常量属性(不可修改,不可重新定义或者删除)


对象常量.png

禁止扩展:

let person = {
        name: "张三",
      };
      Object.preventExtensions(person)
      person.gender = '女';//"TypeError: Cannot add property gender, object is not extensible"
      console.log(person);

密封
Object.seal()会创建一个密封的对象,这个方法实际上会在一个现有对象上调用object.preventExtensions(...)并把所有现有属性标记为configurable:false。

密封.png

所以, 密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以改属性的值)

冻结: vue中纯数据的展示,可以冻结对象,取消绑定,提升性能
Object.freeze()会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(),并把所有现有属性标记为writable: false,这样就无法修改它们的值。


冻结.png

ES6:Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写
基本用法:

let p = new Proxy(target, handler);

参数说明:
1.target :需要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
2.handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数(可以理解为某种触发器)。具体的handler相关函数请查阅官网
①get:属性读取操作的捕捉器

let person = {
    name:'张三',
    age:18
}
person = new Proxy(person,{
    get(target,key) {
        console.log('获取属性');
        if (key === 'age') {
            return target[key] +'岁'
        }
        return target[key];
    }
})

console.log(person.age);//18岁

②set:属性设置操作的捕捉器。

let person = {
    name:'张三',
    age:18
}
person = new Proxy(person,{
    set(target,key,val) {
        console.log('设置属性');
        if(typeof target[key] === 'number'){
            target[key] =  val + '岁';
        }else{
            target[key] = val;
        }
    }
})

person.age = 19;
console.log(person.age);

③has:操作符的捕捉器。检查是否存在属性。

//has
let range= {
    start:1,
    end:5
}
range = new Proxy(range,{
    has:function(target,key){
        return key >= target.start && key <= target.end;
    }
})
console.log(2 in range);//true
console.log(9 in range);//false

④ownkeys:对对象的循环遍历进行拦截

//保护_password不可被遍历
let person = {
    name: '张三',
    age: 18,
    _password: '****'
}
person = new Proxy(person, {
    ownKeys(target) {
        return Object.keys(target).filter(item =>
            !item.startsWith('_')
        )
    }
});
console.log(Object.keys(person));//['name', 'age']

⑤deleteProperty:删除拦截器

let person2 = {
    name: '李四',
    age: 19,
    _password: '****'
}
person2 = new Proxy(person2, {
    deleteProperty(target, prop) {
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            delete target[prop];
            return true;
        }
    }
})
try {
    delete person2._password
} catch (e) {
    console.log(e.message);//不可删除

}

⑥apply拦截函数操作

let sum = function (...args) {
    let sum = 0;
    args.forEach(item => {
        sum += item;
    })
    return sum;
}
sum = new Proxy(sum, {
    apply(target,context,args) {
        return target(...args)*2;
    }
})

console.log(sum(1,2,3));//12
console.log(sum.call(null,1,2,3,4));//20
console.log(sum.apply(null,[1,2,3,4]));//20

⑦construct 拦截new 命令

function People(name){
    this.name = name;
}
console.log(People);
let proxy = new Proxy(People,{
    construct:function(target, argumentsList, newTarget) {
        console.log('拦截到了');
        return new target(...argumentsList);
    }
})
console.log(new proxy('张三'));

proxy拦截器总结:


proxy拦截器总结1.png
proxy拦截器总结2.png

Reflect:

Reflect简介.png
reflect详细介绍

Object.defineProperty与Proxy的区别

相关文章

网友评论

      本文标题:Proxy(代理)

      本文链接:https://www.haomeiwen.com/subject/eeotdrtx.html