前端进阶攻略之ES6中反射和代理

前端进阶攻略之ES6中反射和代理

前端进阶攻略之ES6中反射和代理_第1张图片
在学习ES6中反射和代理之前,先要明白属性描述符和存储器属性的原理,然后理解反射和代理的原理就会非常的简单。

一.属性描述符

在ES5之前,JavaScript语言本身并没有提供可以直接检测属性特性的方法,比如判断属性是否可读,ES5 增加了属性描述符,可以更细腻的控制属性的不同操作。

1.Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor()方法可以查看描述属性的相关信息, 第一个参数为对象,第二个参数为对象的属性值。

let obj={
     
   a:1,
   b:2
}
// Object.getOwnPropertyDescriptor()方法可以查看描述属性的相关信息,
// 第一个参数为对象,第二个参数为对象的属性值。
console.log(Object.getOwnPropertyDescriptor(obj,"a"));

configurable:true 该属性是否被属性描述符修改
enumerable:true 该属性是否可以被枚举
value:1 属性值
writable:true 该属性是否可以被重新赋值

2.Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors()方法可以查看该对象全部属性的描述属性的相关信息, 只有一个参数为对象,查看该对象全部属性的描述属性的相关信息。

let obj={
     
   a:1,
   b:2
}  
console.log(Object.getOwnPropertyDescriptors(obj));

3.Object.defineProperty()

Object.defineProperty()属性修饰符可以修改对象中的属性的相关描述信息,第一个参数为对象,第二个参数为对象中的属性值

let obj = {
     
a: 1,
b: 2
}

// configurable:true  该属性是否被属性描述符修改
// enumerable:true    该属性是否可以被枚举
// value:1            属性值
// writable:true      该属性是否可以被重新赋值
Object.defineProperty(obj, "a", {
     
configurable: true,
enumerable: true,
enumerable: true,
value: 10
});
console.log(obj); //obj.a的值改成了10

4. Object.definePropertys()

Object.definePropertys()属性修饰符可以修改对象中的全部属性的相关描述信息, 第一个参数为对象,可以修改对象中的全部属性的相关描述信息

let obj = {
     
a: 1,
b: 2
}
Object.defineProperties(obj, {
     
            a: {
     
                configurable: true,
                enumerable: true,
                enumerable: true,
                value: 10
            },
            b: {
     
                configurable: true,
                enumerable: true,
                enumerable: true,
                value: 10
            }
});

二.存储器属性

存储器属性: 在控制台的表现形式为(…)
在属性描述符中, 如果配置了get和set任意一个, 则该属性不再是普通属性, 而是存储器属性,set() get() 函数, 如果一个属性为存储器属性, 再获取该属性时, 会运行get方法, 将get方法得到的 返回值作为属性值, 如果给该属性赋值, 则会运行set方法。

let obj = {
     
       a: 1,
       b: 2
}
Object.defineProperty(obj, "a", {
     
            get() {
     
                return _a;
            },
            set(val) {
     
                return _a = val;
        }
});
obj.a = 10;
console.log(obj.a);

在属性描述符中, 如果配置了get和set任意一个, 则该属性不再是普通属性, 而是存储器属性

        let obj = {
     
            a: 1,
            b: 2
        }
        Object.defineProperties(obj, {
     
            a: {
     
                get() {
     
                    return _a;
                },
                set(val) {
     
                    return _a = val;
                }
            },
            c: {
     
                get() {
     
                    return _c;
                },
                set(val) {
     
                    return _c = val;
                }
            }
        });
        obj.c = 10;
        console.log(obj.c);

三.反射Reflect

Reflect(反射)是ES6为更方便的操作对象而提供的新API 。

1.Reflect是什么?

 Reflect是js的内置对象,它提供了一系列的方法,可以让开发者通过调用这些方法,访问一些js底层功能

2.js的底层功能:

属性的取值,赋值,普通函数和构造函数的调用,判断对象的属性,删除对象的属性。。。。。

3.反射可以做什么?

Reflect可以实现底层功能

4.这些功能已经存在,为什么还要用反射来实现?

有一个重要理念,在ES5被提供出:减少代码,让代码更加纯粹这种理念很大程度上受函数式编程思想的影响
ES6进一步贯彻落实这个理念,他认为,对属性内存的控制、原型链的修改,函数的调用等,这些都属于底层实现,
属于一种语法,因此希望提出来,形成一个正常的API,并高度聚集到一个对象中去,于是就形成了Reflest对象

5.Reflect的方法

5.1Reflect.set()给对象的属性赋值

        let obj = {
     
                a: 1,
                b: 2
        }
            // Reflect.set()方法第一个参数为对象,第二个参数为对象的属性,第三个参数为对象的属性值
            // 如果对象中存在该属性的话,就会修改属性值,如果不存在的话,就会为对象添加一个属性
        Reflect.set(obj, "c", 3);
        console.log(obj); //{a: 1, b: 2, c: 3}

Reflect.set()方法第一个参数为对象,第二个参数为对象的属性,第三个参数为对象的属性值,如果对象中存在该属性的话,就会修改属性值,如果不存在的话,就会为对象添加一个属性

5.2Reflect.get()读取对象的属性值

         let obj = {
     
                a: 1,
                b: 2
         }
         console.log(Reflect.get(obj, "a"));

5.3Reflect.apply()
调用函数,并绑定this和参数列表,等同于函数调用

        function func(a, b) {
     
            console.log(this)
            return a + b
        }
        // func(3,4)
        console.log(Reflect.apply(func, null, [3, 4]))

5.4.Reflect.defineProperty()
类似于Object.defineProperty,区别在于Reflect如果配置出现问题,返回false而不是报错, 第一个参数为对象,第二个参数为对象中的属性值,可以用来修改对象的属性值和描述信息

        let obj = {
     
                a: 1,
                b: 2
        }
        Reflect.defineProperty(obj, "a", {
     
            value: 10,
            configurable: false,
            enumerable: false,
            writable: false
        });
        console.log(obj);

5.5Reflect.deleteProperty()
Reflect.deleteProperty()方法,用来删除对象中的属性值

        Reflect.deleteProperty(obj, "a")
        console.log(obj)

5.6.Reflect.construct()
Reflect.construct()使用构造函数的方式创建对象

       function Text(name, sex) {
     
            this.name = name;
            this.sex = sex;
        }
        const t = Reflect.construct(Text, [5, 6]);
        console.log(t); //Text {name: 5, sex: 6}

5.7Reflect.has()
Reflect.has()方法判断一个对象是否拥有一个属性

     console.log('b' in obj)
     console.log(Reflect.has(obj, "a"))

以上都是Reflect的常用方法,详情方法大全可以在该网址学习:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

四.代理Proxy

代理:提供了修改底层实现的方式
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

4.1创建一个Proxy对象

let p = new Proxy(target, handler);

target目标对象 (需要代理的对象)
handler 是一个普通对象,重写底层方法的对象

4.2代理模式Proxy的作用主要体现在三个方面:

  • 拦截和监视外部对对象的访问
  • 降低函数或类的复杂度
  • 在复杂操作前对操作进行校验或对所需资源进行管理
        const obj = {
     
            a: 1,
            b: 2
        }
        const pro = new Proxy(obj, {
     
            set(target, protertyKey, value) {
     
                console.log(`对对象${
       target}设置了${
       protertyKey}属性的值${
       value}`)
                Reflect.set(target, protertyKey, value)
            },
            get(target, protertyKey) {
     
                console.log(`对对象${
       target}设置了${
       protertyKey}属性的值`)
                return Reflect.get(target, protertyKey);
            },
            has(target, protertyKey) {
     
                return Reflect.has(target, protertyKey)
            },
            delete(target, protertyKey) {
     
                return Reflect.delete(target, protertyKey);
            }
        });
        console.log(pro);

Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。

用代理对象创建一个观察者模式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <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(proxy)){
     
                    html += `
                        

${ prop} ${ proxy[prop]}

`
} div.innerHTML = html; } return proxy; } const target = { a : 1, b : 2 } const obj = observer(target) </script> </body> </html>

你可能感兴趣的:(ES6,es6)