yield迭代协议与异步处理、proxy代理、装饰器<前端学习笔记>

1. Iterator 和 for…of 循环

1.1 可迭代协议 与 迭代器协议

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols

1.2 为什么要有两个协议

不可能知道一个特定的对象是否实现了迭代器协议,然而创造一个同时满足迭代器协议和可迭代协议的对象是很容易的
(就像下面的example所示)。这样做允许一个迭代器能被不同希望迭代的语法方式所使用。 因此,很少只实现迭代器协议而不实现可迭代协议。

1.3 都有哪些语法或特性,使用或实现了可迭代协议与迭代器协议

for...of / ... / Array.from 使用了迭代器协议,自制???
[] / Set / Map / generators 实现了Iterators

2. Generator函数与异步应用

1.yield  使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者(返回)
2.基于生成器的版本的return关键字  
3.yield关键字实际返回一个IteratorResult(迭代器)对象,它有两个属性,value和done,分别代表返回值和是否完成。
4.yield无法单独工作,需要配合generator(生成器)的其他函数,如next,懒汉式操作,展现强大的主动控制特性。

function* 定义生成器函数   
1.生成器函数能减少系统存储空间,因为要一次数据,生成器才会生成一次数据,不要不生成。
2.[GeneratorFunction: yie]

2.1 基本用法

function* yie(){
    let list = [1,3,6,9];
    for (let i = 0;i<list.length;i++){
        yield list[i];
    }
}
const myArr = yie();
/* 
1.函数next()是个迭代器对象,传参可以缺省,默认调用函数 。
2.两个属性{value,done} 
*/
console.log(myArr.next(yie()));//{ value: 1, done: false }
console.log(myArr.next());//{ value: 3, done: false }
console.log(myArr.next());//{ value: 6, done: false }
console.log(myArr.next());//{ value: 9, done: false }
console.log(myArr.next());//{ value: undefined, done: true }

2.2 next传递参数

next()函数及参数

  1. next()可以带一个参数,该参数会被认为是上一个yield整体的返回值
  2. 意义:可以在不同阶段从外部直接向内部注入不同的值来调整函数的行为
  3. 第几个next() 就获得第几个yield 的返回对象
function* mygenerator() {
    for (let i = 1; true; i++) {
        let reset = yield i;
        if (reset) {
            console.log(`yield 返回值被改变,函数行为发送变化`);
            i = -1;
        };
    }
}
const myArr = mygenerator();

console.log(myArr.next());//{ value: 1, done: false }
console.log(myArr.next());//{ value: 2, done: false }
console.log(myArr.next());//{ value: 3, done: false }
console.log(myArr.next());//{ value: 4, done: false }
console.log(myArr.next());//{ value: 5, done: false }
// yield 返回的值被赋值为true
console.log(myArr.next(true)); //yield 返回值被改变,函数行为发送变化 { value: 0, done: false }
next() 传参是对yield整体的传参 (把yield也包括进去),否则yield类似于return
function* test(x){
    console.log(`x:${x}`)

    let y = 2*(yield (x+1));
    console.log(`y:${y}`);

    let z = yield (y/3);
    console.log(`z:${z}`);

    return x+y+z;
}
let a = test(5);
console.log(a.next());//x:5 { value: 6, done: false }
console.log(a.next());//y:NaN { value: NaN, done: false }
console.log(a.next());//z:undefined { value: NaN, done: true } //value 是 return的值
分析:
1. x恒为5,所以第一次调用传空没问题,可得到对应的第一个yield返回值:yield (x + 1)
2. 第二次调用,无参数传入,所以y为(2* undefined) => NaN,自然得不到z
3. 第三次调用同上分析
let a = test(5);
console.log(a.next()); //x:5 { value: 6, done: false }
console.log(a.next(12));//y:24 { value: 8, done: false }
console.log(a.next(13));//z:13 { value: 42, done: true }
分析:
1. x恒为5,所以第一次调用传空没问题,可得到对应的第一个yield返回值:yield (x + 1)
2. 第二次调用,传入12,所以y为24 (yield (x + 1) = 入参),得到第二个yield: yield (y / 3) = 8
3. 第三次调用同上分析,得到最后的z值并 return = 42

2.3 用for…of迭代generators

function* liangpiGenerators() {
    console.log('和面之前');
    window.status = yield '和面';
    console.log('和完面了');
    var b = yield '蒸';
    console.log('蒸完了');
    var c = yield '切';
}
for (let item of liangpiGenerators()) {
    console.log('item:', item);
}

2.4 generators处理异步

function buy(name, cb) {
    setTimeout(() => {
        cb && cb(null, name);//cb为真执行cb函数
    }, 5);
}

function buyPromise(name) {
    return new Promise((resolve, reject) => {
        buy(name, (err, content) => {
            if (err) reject();
            else resolve(content);
        })
    })
}


function* buyAmountGenerators() {
    var food1 = yield buyPromise('炸鸡');
    var food2 = yield buyPromise('汉堡' + food1);
    var food3 = yield buyPromise('可乐' + food2);
    var food4 = yield buyPromise('烤鸭' + food3);
    return food4;
}

let buyAmount = buyAmountGenerators();
// 用递归实现 1.异步执行无法直接输出返回值 使用回调函数
function myBuyAmount(food,callBack) {
    let a = buyAmount.next(food);
    if (a.done) return callBack(food);
    a.value.then(res => {
        // console.log("foods:", res);
        myBuyAmount(res,callBack);
    })
}
myBuyAmount(null,food=>{
    console.log(food);//烤鸭可乐汉堡炸鸡
});
//使用Promise
function myBuyAmount() {
    return new Promise((resolve, reject) => {
        (function buy(food) {
            let a = buyAmount.next(food);
            if (a.done) {
                resolve(food);
                return
            };
            a.value.then(res => {
                // console.log("foods:", res);
                buy(res);
            })
        })()
    })
}

myBuyAmount().then(res => {
    console.log(res)
})
//使用co第三方库
var co = require('co');
//自动执行next并将promise的返回值作为下一个next的参数,返回结果是return的结果
co(buyAmountGenerators).then(res =>{
    console.log(res)
})

2.5 封装异步处理函数

类似于co中的使用方式

const co = require('co');
const fetch = require('node-fetch');

co(function *() {
    const res = yield fetch('https://mcs.snssdk.com/v1/list?rdn=0.5130960891765854');
    const jsonRes = yield res.json();

    console.log("jsonRes:", jsonRes);
});

3. async函数

3.1 基本用法

封装隐式的Promise行为,趋近于同步行为,实则为语法糖

async function buyAmountGenerators() {
    var caiContent = await buyPromise('cai');
    var paomianContent = await buyPromise('paomian' + caiContent);
    var shuanghuanglianContent = await buyPromise('shuanghuanglian' + paomianContent);
    return shuanghuanglianContent;
}

3.2 如何封装旧的函数以适应async/await语法

将error first风格的函数,封装为Promise形式的函数即可

function buy(name, cb) {
    setTimeout(() => {
        cb && cb(null, 'content:' + name);
    }, 5);
}
function buyPromise(name) {
    return new Promise((resolve, reject) => {
        buy(name, function (err, content) {
            if (err) {
                reject();
            }
            resolve(content);
        });
    });
}

async function buyAmountAsync() {
    var caiContent = await buyPromise('cai');
    var paomianContent = await buyPromise('paomian' + caiContent);
    var shuanghuanglianContent = await buyPromise('shuanghuanglian' + paomianContent);
    return shuanghuanglianContent;
}

buyAmountAsync().then(content => {
    console.log('content:::::::', content);
});

3.3 babel编译下的generators/async/await

看编译后的源码
generators -> 代码切割
async/await的原理还是老一套(generators)

3.4 优势

比Promise优势

axios()
    .then(function () {
        new Promise(() => {
            reject();
        });
    })
    .then(function () {
        
    })
    .catch(function () {
        // 统一???!!!
    });
  1. 对于流的控制,更加精细化
  2. 直接简单的try-catch体验
  3. 同步的书写体验

4. Proxy与Reflect用法

4.1 基本用法


// obj.name
// obj.money
// obj.money = 100000000;
var obj = {};
//拦截属性对象属性读取和设置
Object.defineProperty(obj, 'money', {
    get(key) {
        console.log('get a attr');
        return obj[key];
    },

    set(key, value) {
        console.log('set a attr');
        return obj[key] = value
    }
});
// obj.money = 100000000;
var obj = {};
var proxiedObj = new Proxy({}, {
    //target:原始对象 key:拦截的属性 receiver:发起调用的对象
    get(target, key, receiver) {
        console.log('key:', key);
    },
    //value:设置的值
    set(target, key, value, receiver) {
        console.log('key:', key, value);
    }
});
proxiedObj.asdasd = 1;

4.2 可撤销对象

var {proxy, revoke} = Proxy.revocable({}, {
    get(target, key, receiver) {
        console.log('key:', key);
    },

    set(target, key, value, receiver) {
        console.log('key:', key, value);
    }
});
//删除拦截
revoke();

4.3 Reflect基本用法

4.4 在Vue3.0中的应用

代理对象与处理对象部分的源码,使用的是Proxy,虽然使用的是TS,但是和ES6中的Proxy与Reflect一致

5. Decorators用法与注意事项

5.3 如何装饰类与方法

//装饰一个类
const itemFy = (target) => {
    console.log('target::::', target);
    target.prototype.click = function (){
        console.log("click");
    }
    return target;
};
//装饰一个类方法  方法定义在类内,函数写在外头
const renderShell = (targetPrototype,propName)=>{

}

@itemFy  //=== itemFy(MyComponent)
//class 是语法糖 === function MyComponent(){}
class MyComponent {
    render() {
        return '<div>内容</div>';
    } 
}

5.4 babel编译下的Decorators

5.5 decorators与proxy的联系与区别

  1. Decorators会更改原始对象,装饰是对于原有对象的修改
  2. Proxy注重于“代理”,产生新的对象,而非对原始的修改

6. class语法

第二节课(面向对象)讲过,同学们可以自行回顾复习

7. babel配置与插件书写

7.1 babel中的术语

Presets

一系列配置的集合

polyfill(腻子)

补丁,用于兼容各个浏览器对于语法支持程度的不同,补充的方法或属性集合

plugin

现在,Babel 虽然开箱即用,但是什么动作都不做。它基本上类似于 const babel = code => code; ,将代码解析之后再输出同样的代码。如果想要 Babel 做一些实际的工作,就需要为其添加插件

7.2 babel-loader在webpack中的注意事项

webpack loader
babel-loader
babel-loader 6.0
babel-plugin-proposal-decorators
babel-preset-env

babel-loader 7.0 @babel/plugin-proposal-decorators

module: {
    use: {
        test: /\.js$/,
        loader: 'babel-loader'
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值