ES 2015/6 新特性匯總


ES 2015/6 新增內容還是比較多的,這里僅大綱性的列舉一下(不一定全面)這些特性。其實,每個點挖進去都會有很多學問在里頭,本文旨在匯總,所以不對這些特性進行深層次的討論及研究。隨后若有時間,再單獨寫幾篇博客對常用的點進行深挖,與大家進行深度交流。

箭頭函數

箭頭函數,通過 => 語法實現的函數簡寫形式,C#/JAVA8/CoffeeScript 中都有類似語法。與函數不同,箭頭函數與其執行下文環境共享同一個 this。如果一個箭頭函數出現在一個函數對象內部,它會與這個函數共享 arguments 變量。

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

// Lexical this
var bob = {
  _name: "Bob",
  _friends: ['jim'],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f)); // Bob knows jim
  }
};

// Lexical arguments
function square() {
  let example = () => {
    let numbers = [];
    for (let number of arguments) {
      numbers.push(number * number);
    }

    return numbers;
  };

  return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

類 Class

Javascript 並不是引入了一個新的面向對象的對象繼承模型,而是基於原型繼承的語法糖。其提供了一個更簡單和清晰的語法來創建對象並處理繼承。

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

類沒有聲明提升,必須確保在調用前已經進行了聲明。

構造函數 constructor 是一個特殊的方法,其用於創建和初始化類的實例。

靜態方法 static 關鍵字用於聲明靜態方法

創建子類 extends 關鍵字用於創建子類,這里要注意:extends 不能用於擴展常規對象(不可構造/非構造的),如果要繼承常規對象,可使用 Object.setPrototypeOf()

調用超類 super 關鍵字可以用來調用父類中的方法

Mix-ins 混合

增強的對象字面量

通過字面量形式可以實現,定義prototype、鍵值對簡寫、定義方法等、動態屬性名稱。

var obj = {
    // Sets the prototype. "__proto__" or '__proto__' would also work.
    __proto__: theProtoObj,
    // Computed property name does not set prototype or trigger early error for
    // duplicate __proto__ properties.
    ['__proto__']: somethingElse,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ "prop_" + (() => 42)() ]: 42
};

模板字符串

模板字符串 提供構造字符串的語法糖,在 Prel/python 等語言中也都有類似特性。

// Basic literal string creation
`This is a pretty little template string.`

// Multiline strings
`In ES5 this is
 not legal.`

// Interpolate variable bindings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Unescaped template strings
String.raw`In ES5 "\n" is a line-feed.`

// Construct an HTTP request prefix is used to interpret the replacements and construction
GET`http://foo.org/bar?a=${a}&b=${b}
    Content-Type: application/json
    X-Credentials: ${credentials}
    { "foo": ${foo},
      "bar": ${bar}}`(myOnReadyStateChangeHandler);

解構賦值

Destructuring 法是一個Javascript表達式,這使得可以將值從數組或屬性從對象提取到不同的變量中。

// list matching
var [a, ,b] = [1,2,3];
a === 1;
b === 3;

// object matching (用新變量名賦值)
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()

// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()

// Can be used in parameter position
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

// 變量可以先賦予默認值。當要提取的對象沒有對應的屬性,變量就被賦予默認值。
var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5

// Destructuring + defaults arguments
function r({x, y, w = 10, h = 10}) {
  return x + y + w + h;
}
r({x:1, y:2}) === 23

// 對象屬性計算名和解構
let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

Default + Rest + Spread

為函數參數提供默認值 & ... 定數量參數

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) {
  // y is an Array
  return x * y.length;
}
f(3, "hello", true) == 6



function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) == 6

Let + Const

let 用於聲明塊級作用域變量。 const 用於聲明常量。

function f() {
  {
    let x;
    {
      // this is ok since it's a block scoped name
      const x = "sneaky";
      // error, was just defined with `const` above
      x = "foo";
    }
    // this is ok since it was declared with `let`
    x = "bar";
    // error, already declared above in this block
    let x = "inner";
  }
}

迭代器

通過 symbol.iterator 可創建自定義迭代器。

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) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}

生成器 Generators

普通函數使用function聲明,而生成器函數使用function*聲明。

在生成器函數內部,有一種類似return的語法:關鍵字yield。二者的區別是,普通函數只可以return一次,而生成器函數可以yield多次(當然也可以只yield一次)。在生成器的執行過程中,遇到yield表達式立即暫停,后續可恢復執行狀態。

function* quips(name) {
  yield "你好 " + name + "!";
  yield "希望你能喜歡這篇介紹ES6的譯文";
  if (name.startsWith("X")) {
    yield "你的名字 " + name + "  首字母是X,這很酷!";
  }
  yield "我們下次再見!";
}

Unicode

// 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 的原生支持

從語言層面支持了模塊和組件,類似 AMD CMD 的機制。隱式的同步加載機制——當模塊加載完成前不會向后執行。

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));

// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));

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

// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));

Map + Set + WeakMap + WeakSet

// 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 =
{
  // target.prop
  get: ...,
  // target.prop = value
  set: ...,
  // 'prop' in target
  has: ...,
  // delete target.prop
  deleteProperty: ...,
  // target(...args)
  apply: ...,
  // new target(...args)
  construct: ...,
  // Object.getOwnPropertyDescriptor(target, 'prop')
  getOwnPropertyDescriptor: ...,
  // Object.defineProperty(target, 'prop', descriptor)
  defineProperty: ...,
  // Object.getPrototypeOf(target), Reflect.getPrototypeOf(target),
  // target.__proto__, object.isPrototypeOf(target), object instanceof target
  getPrototypeOf: ...,
  // Object.setPrototypeOf(target), Reflect.setPrototypeOf(target)
  setPrototypeOf: ...,
  // for (let i in target) {}
  enumerate: ...,
  // Object.keys(target)
  ownKeys: ...,
  // Object.preventExtensions(target)
  preventExtensions: ...,
  // Object.isExtensible(target)
  isExtensible :...
}

Symbols

這里有一篇講 symbols 的文章,非常不錯。
http://www.infoq.com/cn/articles/es6-in-depth-symbols

(function() {

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

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

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

  // Limited support from Babel, full support requires native implementation.
  typeof key === "symbol"
})();

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

Subclassable Built-ins

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

var arr = new MyArray();
arr[1] = 12;
arr.length == 2

Math + Number + String + Object APIs

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].findIndex(x => x == 2) // 1
["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) })

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.

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

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 ES2015
factorial(100000)

有關 ES6/2015 的特性就先匯總到這里,后面補一些常用工具


常用工具 - 持續更新

如果你想在老版本瀏覽器使用 import(),請記得使用 polyfill(例如 es6-promise 或 promise-polyfill)來 shim Promise。import() 在內部依賴於 Promise。

寫在后面

本文地址:https://www.cnblogs.com/kelsen/p/7046004.html

如果您有任何建議或疑問請在下面留言交流。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM