Skip to content

ECMAScript 6 特性速览中文翻译

License

Notifications You must be signed in to change notification settings

10W8K/es6features

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 

Repository files navigation

ECMAScript 6 git.io/es6features

介绍

ECMAScript 6,又称 ECMAScript 2015,是 ECMA 标准的最新版。ES6 重新定义了这门语言,而上一版则要追溯到 09 年发布的 ES5。这里可以看到一份正在兼容此标准的 JavaScript 引擎详单 进行中

查阅 ES6 standard 了解 ECMAScript 6 语言的完整规范。

ES6 包含以下特性:

ECMAScript 6 特性

箭头函数 Arrows

箭头函数是旧式函数写法的语法糖,使用 => 语法。 它的语法跟 C#、Java 8 和 CoffeeScript 的语法类似。 箭头函数的函数体可以是一个语句块,也可以是一个表达式,表达式的结果将作为函数的返回值。 与普通函数不同,箭头函数内部的 this 词法作用域与外部相同。

// 表达式作为函数体
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));

// 语句块作为函数体
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));
  }
}

类支持

ES6 中的类是“基于原型的面向对象模式”的语法糖(注:并不是面向对象)。 以前用 ES5 模拟面向对象的形式太多了, 现在规范了更清晰的语法,提高代码的通用性和语法统一。 类支持原型继承,super 调用,创建实例,静态方法和构造函数。

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    // 调用父类的构造函数
    super(geometry, materials);
    // 增加类的属性成员
    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  // 增加类的方法成员
  update(camera) {
    // 调用父类方法
    super.update();
  }
  // getter 函数
  get boneCount() {
    return this.bones.length;
  }
  // setter 函数
  set matrixType(matrixType) {
    this.idMatrix = SkinnedMesh[matrixType]();
  }
  // 静态函数
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

增强的对象字面量

ES6 增强了对象字面量以便支持以下特性:

  • 构造期间指定对象的原型
  • foo: foo 赋值的简便语法
  • 方法定义
  • super 调用
  • 计算属性

综上,对象字面量和类定义在形式上更加接近了, 对于 ECMAScript 这种基于对象的语言大有裨益。

var obj = {
    // __proto__
    __proto__: theProtoObj,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ 'prop_' + (() => 42)() ]: 42
};

字符串模板

字符串模板为构造字符串提供语法糖, 这与 Perl、Python 和其他语言的字符串插值语法类似。 字符串模板还可以设置一个过滤标签, 用于阻止注入攻击或是其他不应该属于字符串的恶意代码。

// 基本字符串
`In JavaScript '\n' is a line-feed.`

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

// 字符串插值
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// 构造一个 HTTP 请求,前缀用来中断变量替换,以保留原始格式
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);

解构

解构允许通过模式匹配进行值绑定,支持数组和对象的解构。 解构具有良好的容错性,这一点跟检索对象的未定义属性时类似,会得到 undefined

// 列表匹配
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;

// 提供默认值
var [a = 1] = [];
a === 1;

参数默认值 + 可变形参 + 拓展实参

Callee-evaluated default parameter values. Turn an array into consecutive arguments in a function call. Bind trailing parameters to an array. Rest replaces the need for arguments and addresses common cases more directly.

function f(x, y=12) {
  // 若 y 未被赋值或为 undefined,则取 12
  return x + y;
}
f(3) == 15
function f(x, ...y) {
  // y 是一个数组
  return x * y.length;
}
f(3, "hello", true) == 6
function f(x, y, z) {
  return x + y + z;
}
// 把数组的每个元素拓展为函数的参数
f(...[1,2,3]) == 6

Let + Const 关键字

提供块级作用域,letvar 的升级版。 const 定义常量,未赋值不可使用。

function f() {
  {
    let x;
    {
      // okay, 块级变量名
      const x = "sneaky";
      // error, const 值不可修改
      x = "foo";
    }
    // error, 重复定义
    let x = "inner";
  }
}

迭代器 + 新遍历方式

Iterator objects enable custom iteration like CLR IEnumerable or Java Iterable. Generalize for..in to custom iterator-based iteration with for..of. Don’t require realizing an array, enabling lazy design patterns like LINQ.

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) {
  // 1000 时截断序列
  if (n > 1000)
    break;
  console.log(n);
}

Iteration is based on these duck-typed interfaces (using TypeScript type syntax for exposition only):

interface IteratorResult {
  done: boolean;
  value: any;
}
interface Iterator {
  next(): IteratorResult;
}
interface Iterable {
  [Symbol.iterator](): Iterator
}

Generators

Generators simplify iterator-authoring using function* and yield. A function declared as function* returns a Generator instance. Generators are subtypes of iterators which include additional next and throw. These enable values to flow back into the generator, so yield is an expression form which returns a value (or throws).

Note: Can also be used to enable ‘await’-like async programming, see also ES7 await proposal.

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);
}

The generator interface is (using TypeScript type syntax for exposition only):

interface Generator extends Iterator {
    next(value?: any): IteratorResult;
    throw(exception: any);
}

Unicode

Non-breaking additions to support full Unicode, including new Unicode literal form in strings and new RegExp u mode to handle code points, as well as new APIs to process strings at the 21bit code points level. These additions support building global apps in JavaScript.

// same as ES5.1
"𠮷".length == 2

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

// new form
"\u{20BB7}"=="𠮷"=="\uD842\uDFB7"

// new String ops
"𠮷".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "𠮷") {
  console.log(c);
}

Modules

Language-level support for modules for component definition. Codifies patterns from popular JavaScript module loaders (AMD, CommonJS). Runtime behaviour defined by a host-defined default loader. Implicitly async model – no code executes until requested modules are available and processed.

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

Some additional features include export default and export *:

// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}
// app.js
import ln, {pi, e} from "lib/mathplusplus";
alert("2π = " + ln(e)*pi*2);

Module Loaders

Module loaders support:

  • Dynamic loading
  • State isolation
  • Global namespace isolation
  • Compilation hooks
  • Nested virtualization

The default module loader can be configured, and new loaders can be constructed to evaluate and load code in isolated or constrained contexts.

// Dynamic loading – ‘System’ is default loader
System.import('lib/math').then(function(m) {
  alert("2π = " + m.sum(m.pi, m.pi));
});

// Create execution sandboxes – new Loaders
var loader = new Loader({
  global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log('hello world!');");

// Directly manipulate module cache
System.get('jquery');
System.set('jquery', Module({$: $})); // WARNING: not yet finalized

Map + Set + WeakMap + WeakSet

Efficient data structures for common algorithms. WeakMaps provides leak-free object-key’d side tables.

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

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

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

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set

Proxies

Proxies enable creation of objects with the full range of behaviors available to host objects. Can be used for interception, object virtualization, logging/profiling, etc.

// Proxying a normal object
var target = {};
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`;
  }
};

var p = new Proxy(target, handler);
p.world === 'Hello, world!';
// Proxying a function object
var target = function () { return 'I am the target'; };
var handler = {
  apply: function (receiver, ...args) {
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);
p() === 'I am the proxy';

There are traps available for all of the runtime-level meta-operations:

var handler =
{
  get:...,
  set:...,
  has:...,
  deleteProperty:...,
  apply:...,
  construct:...,
  getOwnPropertyDescriptor:...,
  defineProperty:...,
  getPrototypeOf:...,
  setPrototypeOf:...,
  enumerate:...,
  ownKeys:...,
  preventExtensions:...,
  isExtensible:...
}

Symbols

Symbols enable access control for object state. Symbols allow properties to be keyed by either string (as in ES5) or symbol. Symbols are a new primitive type. Optional description parameter used in debugging - but is not part of identity. Symbols are unique (like gensym), but not private since they are exposed via reflection features like Object.getOwnPropertySymbols.

var MyClass = (function() {

  // module scoped symbol
  var key = Symbol("key");

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

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

  return MyClass;
})();

var c = new MyClass("hello")
c["key"] === undefined

Subclassable Built-ins

In ES6, built-ins like Array, Date and DOM Elements can be subclassed.

Object construction for a function named Ctor now uses two-phases (both virtually dispatched):

  • Call Ctor[@@create] to allocate the object, installing any special behavior
  • Invoke constructor on new instance to initialize

The known @@create symbol is available via Symbol.create. Built-ins now expose their @@create explicitly.

// Pseudo-code of Array
class Array {
    constructor(...args) { /* ... */ }
    static [Symbol.create]() {
        // Install special [[DefineOwnProperty]]
        // to magically update 'length'
    }
}

// User code of Array subclass
class MyArray extends Array {
    constructor(...args) { super(...args); }
}

// Two-phase 'new':
// 1) Call @@create to allocate object
// 2) Invoke constructor on new instance
var arr = new MyArray();
arr[1] = 12;
arr.length == 2

Math + Number + String + Array + Object APIs

Many new library additions, including core Math libraries, Array conversion helpers, String helpers, and Object.assign for copying.

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('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

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

Binary and Octal Literals

Two new numeric literal forms are added for binary (b) and octal (o).

0b111110111 === 503 // true
0o767 === 503 // true

Promises

Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future. Promises are used in many existing JavaScript libraries.

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)]);
})

Reflect API

Full reflection API exposing the runtime-level meta-operations on objects. This is effectively the inverse of the Proxy API, and allows making calls corresponding to the same meta-operations as the proxy traps. Especially useful for implementing proxies.

// No sample yet

Tail Calls

Calls in tail-position are guaranteed to not grow the stack unboundedly. Makes recursive algorithms safe in the face of unbounded inputs.

function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES6
factorial(100000)

About

ECMAScript 6 特性速览中文翻译

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published