Learn ES2015

参考(https://segmentfault.com/a/1190000003818502)

毕业到现在都没正经学过js,最近在看vue发现我的js就是土著啊。什么时候冒出这种写发

  1. 箭头函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 使用表达式(Expression bodies)
    var odds = evens.map(v => v + 1);
    var nums = evens.map((v, i) => v + i);

    // 使用函数体(Statement bodies)
    nums.forEach(v => {
    if (v % 5 === 0)
    fives.push(v);
    });

    // this 对象
    var bob = {
    _name: "Bob",
    _friends: [],
    printFriends() {
    this._friends.forEach(f =>
    console.log(this._name + " knows " + f)
    );
    },
    // _printFriend 为译者添加 是使用function时的等价写法
    _printFriends() {
    this._friends.forEach(function(f){
    console.log(this._name + " knows " + f)
    }.bind(this))
    }
    };
  2. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class SkinnedMesh extends THREE.Mesh {
    constructor(geometry, materials) {
    // 调用父类的构造函数 super是父类的实例
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
    }
    update(camera) {
    //...
    super.update();
    }
    // 静态方法
    static defaultMatrix() {
    return new THREE.Matrix4();
    }
    }
  3. ==增强的对象字面量==(这里我先打个问号,不知道他增强了什么。因为我之前也不知道他干了什么,有待后期!!)

  4. 模板字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 创建基本的模板字符串
    `This is a pretty little template string.`

    // 多行字符串
    `In ES5 this is
    not legal.`

    // 插入变量
    var name = "Bob", time = "today";
    `Hello ${name}, how are you ${time}?`

    // 在模板字符串中不使用转义
    String.raw`In ES5 "\n" is a line-feed.`

    // 创建一个HTTP请求头的模板字符串,通过替换内容来构建请求
    GET`http://foo.org/bar?a=${a}&b=${b}
    Content-Type: application/json
    X-Credentials: ${credentials}
    { "foo": ${foo},
    "bar": ${bar}}`(myOnReadyStateChangeHandler);
  5. 解构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 列表(数组)匹配
    var [a, , b] = [1,2,3];

    // 对象匹配
    var { op: a, lhs: { op: b }, rhs: c }
    = getASTNode()

    // 对象匹配的简写
    // 绑定当前作用域的 `op`, `lhs` 和 `rhs`
    var {op, lhs, rhs} = getASTNode()

    // 可以用在函数的参数中
    function g({name: x}) {
    console.log(x);
    }
    g({name: 5})

    // 弱化解构
    var [a] = [];
    a === undefined;

    // Fail-soft destructuring with defaults
    var [a = 1] = [];
    a === 1;
  6. 默认参数(Default) + 不定参数(Rest) + 扩展运算符(Spread)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //默认参数
    function f(x, y=12) {
    // y is 12 if not passed (or passed as undefined)
    return x + y;
    }
    f(3) == 15

    //不定参数
    function f(x, ...y) {
    // ...运算符将x之后的参数转换为名为y的数组
    return x * y.length;
    }
    f(3, "hello", true) == 6

    //扩展运算符
    function f(x, y, z) {
    return x + y + z;
    }
    // ...运算符将数组转换为连续的参数
    f(...[1,2,3]) == 6
  7. Let(局部变量) + Const(常量)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function f() {
    {
    let x;
    {
    // 可以执行,因为是在块级作用域内
    const x = "sneaky";
    // 错误,常量不允许被赋值
    x = "foo";
    }
    // 可以执行,因为是使用let声明
    x = "bar";
    // 错误,在当前块级作用域内已经被声明了一次
    let x = "inner";
    }
    }
  8. 迭代器(Iterators) + For..Of循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 实现斐波那契数列的迭代器
    let fibonacci = {
    [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
    next() {
    [pre, cur] = [cur, pre + cur];
    return { done: false, value: cur }
    }
    }
    }
    }

    for (var n of fibonacci) {
    // 循环将在n > 1000 时结束
    if (n > 1000)
    break;
    console.log(n);
    }

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

可迭代协议:为了变成可迭代对象, 一个对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链prototype chain上的某个对象)必须有一个名字是 Symbol.iterator 的属性(返回一个对象的无参函数,被返回对象符合==迭代器协议==)
当一个对象需要被迭代的时候(比如开始用于一个for..of循环中),它的@@iterator方法被调用并且无参数,然后返回一个用于在迭代中获得值的迭代器。

迭代器协议:它实现了一个 next() 的方法并且返回{ done: false, value: cur }

done (boolean)
如果迭代器已经经过了被迭代序列时为 true。这时 value 可能描述了该迭代器的返回值。返回值在这里有更多解释。
如果迭代器可以产生序列中的下一个值,则为 false。这等效于连同 done 属性也不指定。
value - 迭代器返回的任何 JavaScript 值。done 为 true 时可省略

  1. Generator(和py的生成器类似)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 实现斐波那契数列
    var fibonacci = {
    [Symbol.iterator]: function*() {
    var pre = 0, cur = 1;
    for (;;) {
    var temp = pre;
    pre = cur;
    cur += temp;
    yield cur;
    }
    }
    }

    for (var n of fibonacci) {
    // truncate the sequence at 1000
    if (n > 1000)
    break;
    console.log(n);
    }
  2. 模块

    1
    2
    3
    4
    5
    // lib/math.js
    export function sum(x, y) {
    return x + y;
    }
    export var pi = 3.141593;
1
2
3
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
1
2
3
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));

以及一些额外的功能:export default和export *

1
2
3
4
5
6
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}

1
2
3
// app.js
import exp, {pi, e} from "lib/mathplusplus";
alert("2π = " + exp(pi, e));
  1. 模块加载器(Module Loaders)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 动态加载 – ‘System’ 是默认的加载器
    System.import("lib/math").then(function(m) {
    alert("2π = " + m.sum(m.pi, m.pi));
    });

    // 创建执行沙箱 – new Loaders
    var loader = new Loader({
    global: fixup(window) // replace ‘console.log’
    });
    loader.eval("console.log(\"hello world!\");");

    // 直接操作模块的缓存
    System.get("jquery");
    System.set("jquery", Module({$: $})); // WARNING: not yet finalized
  2. Map + Set + WeakMap + WeakSet

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // Sets
    var s = new Set();
    s.add("hello").add("goodbye").add("hello");
    s.size === 2; //true
    s.has("hello") === true; //true

    // Maps
    var m = new Map();
    m.set("hello", 42);
    m.set(s, 34);
    m.get(s) == 34; //true

    // Weak Maps
    var wm = new WeakMap();
    wm.set(s, { extra: 42 });
    wm.size === undefined

    // Weak Sets
    var ws = new WeakSet();
    ws.add({ data: 42 });
    // 由于传入的对象没有其他引用,故将不会被set保存。
    //这些作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。
  3. Proxies(代理对象)

参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

1
2
3
4
5
6
7
8
9
10
// 代理普通对象
var target = {};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}!`;
}
};

var p = new Proxy(target, handler);
p.world === "Hello, world!"; //true

target:用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler:一个对象,其属性是当执行一个操作时定义代理的行为的函数。

  1. Symbols
    Symbol对对象的状态进行访问控制。Symbol允许对象的属性不仅可以通过string(ES5)命名,还可以通过symbol命名。symbol是一种基本数据类型。可选的name参数用于调试——但并不是他本身的一部分。Symbol是唯一的,但不是私有的,因为他们使用诸如Object.getOwnPropertySymbols这样的方法来使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    (function() {

    // 模块内的symbol
    var key = Symbol("key");

    function MyClass(privateData) {
    this[key] = privateData;
    }

    MyClass.prototype = {
    doStuff: function() {
    ... this[key] ...
    }
    };

    // 被Babel部分支持,原生环境可以完全实现。
    typeof key === "symbol"
    })();

    var c = new MyClass("hello")
    c["key"] === undefined
  2. 可以创建内建对象的子类

    1
    2
    3
    4
    5
    6
    7
    8
    // 创建Array的子类
    class MyArray extends Array {
    constructor(...args) { super(...args); }
    }

    var arr = new MyArray();
    arr[1] = 12;
    arr.length == 2
  3. Math + Number + String + Object APIs

新增很多功能,如核心的Math库,数组转换和用于对象复制的Object.assign()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll("*")) // 将类似数组的对象转换为真正的数组
Array.of(1, 2, 3) // 类似与new Array(),但是当仅有一个参数时,两者表现不同
[0, 0, 0].fill(7, 1) // [0,7,7]
[1,2,3].findIndex(x => x == 2) // 1
["a", "b", "c"].entries() // 迭代结果 [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // 迭代结果 0, 1, 2
["a", "b", "c"].values() // 迭代结果 "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })

  1. 二进制和八进制字面量

    1
    2
    0b111110111 === 503 // true
    0o767 === 503 // true
  2. Promises

Promises是一种异步编程的方式。Promises在将来可能会得到支持。目前很多的JavaScript库都使用了Promises。
参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

1
2
3
4
5
6
7
8
9
10
11
12
13
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}

var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})

  1. Reflect API
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var O = {a: 1};
    Object.defineProperty(O, 'b', {value: 2});
    O[Symbol('c')] = 3;

    Reflect.ownKeys(O); // ['a', 'b', Symbol(c)]

    function C(a, b){
    this.c = a + b;
    }
    var instance = Reflect.construct(C, [20, 22]);
    instance.c; // 42

总结:以上只是初步了解,相信在之后的js路上会经常遇到