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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容