Skip to content
<

ES6 规范详解

1. Iterator 和 for...of 循环

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

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

1.2 为什么要有两个协议

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

自定义可迭代对象

js
var inHomeYou = {
    /* 迭代器协议 */
    s: 0,
    next() {
        const actions = ['dy', 'wzry', 'cf', 'sj'];
        if (this.s >= actions.length) {
            return {
                done: true
            };
        }
        return {
            done: false,
            value: actions[this.s++]
        };
    },
    /* 可迭代协议 */
    [Symbol.iterator]: function () {
        return this;
    }
};

// for (let item of inHomeYou) {
//     console.log('item::', item);
// }
console.log(Array.from(inHomeYou));
js
var o = {
    s: [1, 2, 3],
    name: 'aw'
};
var ret = Object.values(o);
console.log(o[Symbol.iterator]);
console.log(ret[Symbol.iterator]().next());

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

for...of / ... / Array.from 使用了迭代器协议

[] / Set / Map / generators 实现了 Iterators

2. Generator函数与异步应用

2.1 基本用法

js
var a;
function* liangpiGenerators() {
    console.log('开始和面');
    a = yield '和面';
    console.log('和面完了');
    var b = yield '蒸';
    var c = yield '切';
}

/* 返回一个实现了可迭代协议和迭代器协议的句柄 */
var handler = liangpiGenerators();
handler.next();
console.log(a);
handler.next();
console.log(a);

2.2 next 传递参数

js
function* liangpiGenerators() {
    console.log('开始和面');
    global.status = yield '和面';
    console.log('和面完了');
    var b = yield '蒸';
    var c = yield '切';
}

/* 返回一个实现了可迭代协议和迭代器协议的句柄 */
var handler = liangpiGenerators();
handler.next();
handler.next('累');
console.log(global.status);

2.3 用 for...of 迭代 generators

js
function* liangpiGenerators() {
    console.log('开始和面');
    global.status = yield '和面';
    console.log('和面完了');
    var b = yield '蒸';
    var c = yield '切';
}

for (let item of liangpiGenerators()) {
    console.log('item:', item);
}

2.4 generators 处理异步

js
function buy(name, cb) {
    setTimeout(() => {
        cb && cb(null, 'content: ' + name);
    }, 1000);
}

// buy('cai', function (err, content) {
//     console.log(content);
// });

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

// buyPromise('cai').then(console.log);

/* generators买单个东西 */
// function *buyGenerators(name) {
//     yield buyPromise(name);
// }
// let buyTask = buyGenerators('cai');
// buyTask.next().value.then(console.log);

/* generators买多个东西 */
function* buyAmountGenerators() {
    var caiContent = yield buyPromise('菜');
    var paomianContent = yield buyPromise('泡面' + caiContent);
    var shuanghuanglianContent = yield buyPromise('双黄连' + paomianContent);
    return shuanghuanglianContent;
}

// let buyTask = buyAmountGenerators();
// buyTask.next().value.then(res => {
//     buyTask.next(res).value.then(res => {
//         buyTask.next(res).value.then(console.log);
//     });
// });

/* 递归实现主动调用generators */
function runGenerators(handler) {
    return Promise.resolve()
        .then(function nextAction(value) {
            var next = handler.next(value);
            if (next.done) {
                return next.value;
            }
            return Promise.resolve(next.value).then(nextAction);
        });
}
runGenerators(buyAmountGenerators()).then(console.log);

2.5 封装异步处理函数

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

/* generators买多个东西 */
function* buyAmountGenerators() {
    var caiContent = yield buyPromise('菜');
    var paomianContent = yield buyPromise('泡面' + caiContent);
    var shuanghuanglianContent = yield buyPromise('双黄连' + paomianContent);
    return shuanghuanglianContent;
}

/* 类似如下的co库
function runGenerators(handler) {
    return Promise.resolve()
        .then(function nextAction(value) {
            var next = handler.next(value);
            if (next.done) {
                return next.value;
            }
            return Promise.resolve(next.value).then(nextAction);
        });
}
runGenerators(buyAmountGenerators()).then(console.log);
*/
var co = require('co');
co(buyAmountGenerators()).then(console.log);

类似于co中的使用方式

讲义中的

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

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

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

自己写的

js
/* index.mjs 注意: mjs结尾 */
import co from 'co';
import fetch from 'node-fetch';

co(function* () {
    const ret = yield fetch('https://mcs.snssdk.com/v1/list?rdn=0.5130960891765854');
    const res = yield ret.text();
    console.log("res:", res);
    return res;
}).then(console.log);

3. async 函数

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

3.1 基本用法

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

js
async function buyAmountAsync() {
    var caiContent = await buyPromise('菜');
    var paomianContent = await buyPromise('泡面' + caiContent);
    var shuanghuanglianContent = await buyPromise('双黄连' + paomianContent);
    return shuanghuanglianContent;
}

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

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

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

async function buyAmountAsync() {
    var caiContent = await buyPromise('菜');
    var paomianContent = await buyPromise('泡面' + caiContent);
    var shuanghuanglianContent = await buyPromise('双黄连' + paomianContent);
    return shuanghuanglianContent;
}
buyAmountAsync();

3.3 babel 编译下的generators/async/await

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

3.4 比Promise的优势

js
axios()
    .then(function () {
        // 终止
    })
    .then(function () {
        
    })
    .catch(function () {
        
    });
  1. 对流的控制更加精细化

  2. 直接简单的try-catch体验

  3. 同步的书写体验

4. Proxy 与 Reflect 用法

4.1 基本用法

老式用法

js
// obj.name
// obj.money
// obj.money = 10000;
var obj = {};
var m = 0;
Object.defineProperty(obj, 'money', {
    get() {
        console.log('get an attr');
        return m;
    },
    set(val) {
        console.log('set an attr');
        m = val;
    }
});
obj.money = 100000;
console.log(obj.money);
js
var obj = {};
var proxyObj = new Proxy(obj, {
    get(target, p, receiver) {
        console.log(target, p, receiver);
    },
    set(target, p, value, receiver) {
        console.log(target, p, value, receiver);
    }
});

4.2 可撤销对象

js
var {proxy, revoke} = Proxy.revocable({}, {
    get(target, p, receiver) {
        console.log(target, p, receiver);
    },
    set(target, p, value, receiver) {
        console.log(target, p, value, receiver);
    }
})
revoke();
console.log(proxy.name);

4.3 Reflect 基本用法

4.4 在 Vue3.0 中的应用

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

5. Decorators 用法与注意事项

5.3 如何装饰类与方法

js
const itemFy = (target) => {
    console.log('target:::', target);
    target.prototype.click = function () {
        console.log('click');
    };
}

/* 实现装饰器传参 */
const renderShell = (clickable) => {
    return (targetPrototype, propName) => {
        const originRender = targetPrototype[propName];
        targetPrototype[propName] = function () {
            const prefix = clickable ? '<div class="outer" onclick="aw">' : '<div class="outer">';
            return prefix + originRender.call(this) + '</div>';
        }
        return targetPrototype;
    };
}

const renderSpan = () => {
    return (targetPrototype, propName) => {
        const originRender = targetPrototype[propName];
        targetPrototype[propName] = function () {
            return originRender.call(this) + '<span>x</span>';
        }
        return targetPrototype;
    };
}

@itemFy
class MyComponent {
    @renderShell(true)
    @renderSpan
    render() {
        return '<div>内容</div>';
    }

    // @renderShell(false)
    // renderTwo() {
    //     return '<div>内容</div>';
    // }
}

5.4 babel 编译下的Decorators

5.5 decoratorsproxy的联系与区别

  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-loader 7.0 @babel/plugin-proposal-decorators