iterator和Proxy

1iterator(迭代器)

迭代器是一种接口、一种机制。
为各种不同的数据结构提供统一的访问机制,部署了iterator接口的数据结构就可是执行遍历操作。(主要是for......of)。

1.1iterator本质

Iterator本质上,就是一个指针对象。

过程是这样的:

(1)创建一个指针对象,指向当前数据结构的起始位置。

(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

1.2普通函数实现iterator

        function myTest(obj) {
            let i = 0;
            return {
                next() {
                    let done = (i >= obj.length);
                    let value = done ? undefined : obj[i++];
                    return {
                        done,
                        value
                    }

                }
            }
        }
        let str = 'abc';
        let test = myTest(str);
        test.next();//{done : false, value: "a"}
        test.next()//{done : false, value: "b"}
        test.next()//{done : false, value: "c"}
        test.next()//{done : true, value: undefined}

原生具备 Iterator 接口的数据结构如下。

Array
Map
Set
String
函数的 arguments 对象
NodeList 对象
(1)数组

         let arr = [1, 2, 3];
        let iter = arr[Symbol.iterator]();
        iter.next(); //{done: false, value: 1}
        iter.next(); //{done: false, value: 2}
        iter.next(); //{done: false, value: 3}
        iter.next(); //{done: true, value: undefined}

(2)Map

        let map = new Map();
        map.set(0, 1).set(1, 2).set(2, 3);
        let iter = map[Symbol.iterator]();
        iter.next();//{value: [0,1], done: false}
        iter.next();//{value: [1,2], done: false}
        iter.next();//{value: [2,3], done: false}
        iter.next();//{value: undefined, done: true}

(3)Set

        let set = new Set([1,2,3,2]);
        let iter = set[Symbol.iterator]();
        iter.next();//{value: 1, done: false}
        iter.next();//{value: 2, done: false}
        iter.next();//{value: 3, done: false}
        iter.next();//{value: undefined, done: true}

(4)Arguments

       function myTest(a,b,c){
            let iter = arguments[Symbol.iterator]();
            console.log(iter.next());// {value: 1, done: false}
            console.log(iter.next());// {value: 2, done: false}
            console.log(iter.next());// {value: 3, done: false}
            console.log(iter.next());// {value: undefined, done: true}

        }
        myTest(1,2,3)

(5)NodeList

    <ul>
        <li></li>
        <li></li>
        <li></li>
    </ul>
      let ali = document.getElementsByTagName('li');
        let iter = ali[Symbol.iterator]();
        iter.next();//{value:li,done:false};
        iter.next();//{value:li,done:false};
        iter.next();//{value:li,done:false};
        iter.next();//{value:undefined,done:true};

2Proxy代理

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
使用方法:

let proxy = new Proxy(target, handle);

如果没有拦截行为;(handle为{})

        let obj = {};
        let handle = {};
        let proxy = new Proxy(obj, handle);
        proxy.a = 1;
        obj.a; //1

proxy通向原对象。

2.1get()捕获器

        let obj = {
            a: 1,
            b: 2
        };
        let proxy = new Proxy(obj, {
                get(target, prop,receiver) {
                    if (prop in target) {
                        return target[prop];
                    } else {
                        throw new Error(`没找到 ${prop}`)
                    }
                }
            })

或者通过反射API方法;

        let proxy = new Proxy(obj, {
                get(target, prop, receiver) {
                    return Reflect.get(...arguments);
                }
            })

get中接受三个参数第一个就是目标对象(这里是obj),第二个是属性,第三个是代理对象(这里是proxy)。

2.2 set()捕获器

        let obj = {
            a: 1,
            b: 2
        };
        let proxy = new Proxy(obj, {
                set(target, prop, value, receiver) {
                    if (typeof value == 'number') {
                        target[prop] = value
                    } else {
                        throw new Error(`${value} 不是数字`)
                    }
                }

            })

或者通过反射API方法;

        let proxy = new Proxy(obj, {
                set(target, prop, value,receiver) {
                    return Reflect.set(...arguments);
                }
            })

这里多了的value是输入的新的属性。

2.3 deleteProperty()捕获器

        let obj = {
            a: 1,
            b: 2
        };
        let proxy = new Proxy(obj, {
                deleteProperty(target, prop, receiver) {
                    if (prop in target) {
                        delete target[prop];
                    } else {
                        throw new Error(`没找到 ${prop}`)
                    }
                    return delete target[prop];//判断是否删除成功

                }

            })

或者通过反射API方法;

        let proxy = new Proxy(obj, {
                deleteProperty(target, prop,,receiver) {
                    return Reflect.deleteProperty(...arguments);
                }
            })
delete proxy.a//true

2.4 has()捕获器

        let obj = {
            a: 1,
            b: 2
        };
        let proxy = new Proxy(obj, {
                has(target, prop,receiver) {
                    return prop in target                    
                }

            })

或者通过反射API方法;

        let proxy = new Proxy(obj, {
                has(target, prop,,receiver) {
                    return Reflect.has(...arguments);
                }
            })
'a' in proxy;//true 

2.5apply()捕获器,拦截函数;

function fn(){
    return '哈哈'
}
var newFn = new Proxy(fn,{
    apply(){
        return '我已经拦截了函数'
    }

})

console.log(newFn());//'我已经拦截了函数'

或者通过反射API方法;

        let proxy = new Proxy(obj, {
                apply(target, thisArg,...arguments) {
                    return Reflect.apply(...arguments);
                }
            })

Reflect.apply(target,context,args) 有三个参数

target: 需要调用的函数

context: this指向

args : 参数数组。

2.6 revocable()取消代理

Proxy.revocable方法返回一个可取消的 Proxy 实例。

       let obj = {};
        let {
            proxy,
            revoke
        } = Proxy.revocable(obj, {});
        proxy.a = 10;
        obj.a;//10
        revoke();
        proxy.a;//TypeError;
        obj.a;//10

Proxy.revocable方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。上面代码中,当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误。

2.7 defineProperty()

给目标对象定义属性

        const myTarget = {};
        const proxy = new Proxy(myTarget, {
            defineProperty(target, property, descriptor) {
                console.log(target); //{}
                console.log(property); //foo
                console.log(descriptor); //{value:'bar'}
                return Reflect.defineProperty(...arguments)
            }
        });
        Object.defineProperty(proxy, 'foo', {
            value: 'bar'
        });

2.8 Ownkeys()

返回包含字符串或符号的可枚举对象。

        const myTarget = {
            0: 'a',
            1: 'b'
        };
        const proxy = new Proxy(myTarget, {
            ownKeys(target) {
                return Reflect.ownKeys(...arguments)
            }
        });
        console.log(Object.keys(proxy));//['0', '1'];

2.9 getPrototypeOf()

返回描述对象,没有返回null

const myTarget = {};
const proxy = new Proxy(myTarget, {
 getPrototypeOf(target) {
 console.log('getPrototypeOf()');
 return Reflect.getPrototypeOf(...arguments)
 }
});
Object.getPrototypeOf(proxy); 

2.10 setPrototypeOf()

设置原型

const myTarget = {};
const proxy = new Proxy(myTarget, {
 setPrototypeOf(target) {
 console.log('getPrototypeOf()');
 return Reflect.setPrototypeOf(...arguments)
 }
});
Object.setPrototypeOf(proxy); 

2.11 getOwnPropertyDescriptor

返回描述对象,没有返回null

const myTarget = {};
const proxy = new Proxy(myTarget, {
 getOwnPropertyDescriptor(target, property) {
 console.log('getOwnPropertyDescriptor()');
 return Reflect.getOwnPropertyDescriptor(...arguments)
 }
});
Object.getOwnPropertyDescriptor(proxy, 'foo'); 

2.11 getOwnPropertyDescriptor

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容