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 中的Proxy与Reflect一致

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