[譯] You Might Not Need ES6

snowLu發表於2019-03-03

語法目錄

  1. 箭頭函式
  2. 塊級作用域
  3. 模板字串
  4. 計算屬性
  5. 解構賦值
  6. 預設引數
  7. Iterators 和 For-Of 迴圈
  8. Class
  9. Modules
  10. 數字字面量
  11. 屬性賦值方法
  12. 物件屬性的簡介表示
  13. Rest 引數
  14. 擴充套件運算子
  15. Proxy
  16. 類陣列

箭頭函式

與函式表示式相比,箭頭函式表示式(也稱為胖箭頭函式)的語法更簡介,並且不會建立自己的 this
箭頭函式相當於匿名函式。

ES6:

[1, 2, 3].map(n => n * 2);
// -> [ 2, 4, 6 ]
複製程式碼

ES5 實現:

[1, 2, 3].map(function(n) { return n * 2; }, this);
// -> [ 2, 4, 6 ]
複製程式碼

ES6:

var evens = [2, 4, 6, 8, 10];

// 表示式正文
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);

console.log(odds);
// -> [3, 5, 7, 9, 11]

console.log(nums);
// -> [2, 5, 8, 11, 14]

// 宣告式正文
var fives = [];
nums = [1, 2, 5, 15, 25, 32];
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

console.log(fives);
// -> [5, 15, 25]

// 作用域中的 this
var bob = {
  _name: `Bob`,
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + ` knows ` + f));
  }
}
複製程式碼

ES5:

`use strict`;

var evens = [2, 4, 6, 8, 10];

// 表示式正文
var odds = evens.map(function (v) {
  return v + 1;
}, this);
var nums = evens.map(function (v, i) {
  return v + i;
}, this);

console.log(odds);
// -> [3, 5, 7, 9, 11]

console.log(nums);
// -> [2, 5, 8, 11, 14]

var fives = [];
nums = [1, 2, 5, 15, 25, 32];

// 宣告式正文
nums.forEach(function (v) {
  if (v % 5 === 0) {
    fives.push(v);
  }
}, this);

console.log(fives);
// -> [5, 15, 25]

// Lexical this
var bob = {
  _name: `Bob`,
  _friends: [],
  printFriends: function printFriends() {
    this._friends.forEach(function (f) {
      return console.log(this._name + ` knows ` + f);
    }, this);
  }
};
複製程式碼

塊級作用域函式

塊作用域繫結提供了函式和頂級作用域以外的作用域。
這確保你的變數不會超出他們定義的範圍內。

ES6:

// let 宣告一個區域性塊作用域,在 ES6 中可以任意的初始化一個值

`use strict`;

var a = 5;
var b = 10;

if (a === 5) {
  let a = 4; // 作用域在 if 塊中
  var b = 1; // 作用域在函式內部

  console.log(a);  // 4
  console.log(b);  // 1
}

console.log(a); // 5
console.log(b); // 1
複製程式碼

ES5:

`use strict`;

var a = 5;
var b = 10;

if (a === 5) {
  // 在實現上更像下面這樣
  (function () {
    var a = 4;
    b = 1;

    console.log(a); // 4
    console.log(b); // 1
  })();
}

console.log(a); // 5
console.log(b); // 1
複製程式碼

ES6:

// const 在 ES6 中建立只讀的屬性常量
`use strict`;
// 將 favorite 定義為常量並且賦值為 7
const favorite = 7;
// 試圖覆蓋常量
try {
  favorite = 15;
} catch (err) {
  console.log(`my favorite number is still: ` + favorite);
  // 仍然會輸出 7
}
複製程式碼

ES5:

// 將 favorite 定義為一個不可寫的“常量”,並將其賦值為 7。
Object.defineProperties(window, {
  favorite: {
    value: 7,
    enumerable: true
  }
});
// 屬性描述預設為 false,並且 const 是可列舉的
// 試圖覆蓋常量
favorite = 15;
// 仍然會輸出 7
console.log(`my favorite number is still: ` + favorite);
複製程式碼

模版字串

ES6 模版字串是可以包含嵌入表示式的字串,有時也被叫做插值表示式

ES6:

// 表示式佔位符的基本用法
var person = `Addy Osmani`;
console.log(`Yo! My name is ${person}!`);

// 表示式也可以用在物件中
var user = {name: `Caitlin Potter`};
console.log(`Thanks for getting this into V8, ${user.name}.`);

// 插值表示式:作用之一可以用來計算
var a = 50;
var b = 100;
console.log(`The number of JS frameworks is ${a + b} and not ${2 * a + b}.`);

// 多行字串不需要換行符
console.log(`string text line 1
string text line 2`);

// 函式內部表示式
function fn() { return `result`; }
console.log(`foo ${fn()} bar`);
複製程式碼

ES5:

`use strict`;

// 表示式佔位符的基本用法
var person = `Addy Osmani`;
console.log(`Yo! My name is ` + person + `!`);

// 表示式也可以用在物件中
var user = { name: `Caitlin Potter` };
console.log(`Thanks for getting this into V8, ` + user.name + `.`);

// 插值表示式:作用之一可以用來計算
var a = 50;
var b = 100;
console.log(`The number of JS frameworks is ` + (a + b) + ` and not ` + (2 * a + b) + `.`);

// 多行字串
console.log(`string text line 1
string text line 2`);
// 或者下面這種寫法
console.log(`string text line 1

string text line 2`);

// 函式內部表示式
function fn() {
  return `result`;
}
console.log(`foo ` + fn() + ` bar`);
複製程式碼

計算屬性

計算屬性名允許你基於表示式在物件文字中指定屬性

ES6:

var prefix = `foo`;
var myObject = {
  [prefix + `bar`]: `hello`,
  [prefix + `baz`]: `world`
};

console.log(myObject[`foobar`]);
// -> hello
console.log(myObject[`foobaz`]);
// -> world
複製程式碼

ES5:

`use strict`;

var prefix = `foo`;
var myObject = {};

myObject[prefix + `bar`] = `hello`;
myObject[prefix + `baz`] = `world`;

console.log(myObject[`foobar`]);
// -> hello
console.log(myObject[`foobaz`]);
// -> world
複製程式碼

解構賦值

解構賦值語法是一個JavaScript表示式,它可以使用陣列對映和物件文字構造的語法從陣列和物件中提取值,對變數進行賦值。

ES6:

var {foo, bar} = {foo: `lorem`, bar: `ipsum`};
// foo => lorem and bar => ipsum
複製程式碼

ES5:

`use strict`;

var _ref = { foo: `lorem`, bar: `ipsum` };

// foo => lorem and bar => ipsum
var foo = _ref.foo;
var bar = _ref.bar;
複製程式碼

ES3:

with({foo: `lorem`, bar: `ipsum`}) {
  // foo => lorem and bar => ipsum
}
複製程式碼

ES6:

var [a, , b] = [1,2,3];
複製程式碼

ES6 (shimming using Symbol.iterator):

`use strict`;

var _slicedToArray = function (arr, i) {
  if (Array.isArray(arr)) {
    return arr;
  } else {
    var _arr = [];

    for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
      _arr.push(_step.value);

      if (i && _arr.length === i) {
        break;
      }
    }

    return _arr;
  }
};

var _ref = [1, 2, 3];

var _ref2 = _slicedToArray(_ref, 3);

var a = _ref2[0];
var b = _ref2[2];
複製程式碼

ES5:

String.prototype.asNamedList = function () {
  return this.split(/s*,s*/).map(function (name, i) {
    return name ? (`var ` + name + `=slice(` + i + `, ` + (i + 1) + `)[0]`) : ``;
  }).join(`;`);
};

with([1,2,3]) {
  eval(`a, , b`.asNamedList());
}
複製程式碼

預設引數

預設引數允許函式具有可選引數,而不需要檢查引數的長度或是否未定義。

ES6:

function greet(msg=`hello`, name=`world`) {
  console.log(msg,name);
}

greet();
// -> hello world
greet(`hey`);
// -> hey world
複製程式碼

ES5:

`use strict`;

function greet() {
  // 如果像這樣訪問 arguments[0],則可以簡單地進行訪問 msg 變數名
  var msg = arguments[0] === undefined ? `hello` : arguments[0];
  var name = arguments[1] === undefined ? `world` : arguments[1];
  console.log(msg, name);
}

function greet(msg, name) {
  (msg === undefined) && (msg = `hello`);
  (name === undefined) && (name = `world`);
  console.log(msg,name);
}

// 對未定義的引數進行檢查的基本方法
function greet(msg, name) {
  console.log(
    defaults(msg, `hello`),
    defaults(name, `world`)
  );
}

greet();
// -> hello world
greet(`hey`);
// -> hey world
複製程式碼

ES6:

function f(x, y=12) {
  // y 的指是 12 如果沒有接收(或者接收的是 undefined )
  return x + y;
}

f(3) === 15;
複製程式碼

ES5:

`use strict`;

function f(x, y) {
  if (y === undefined) {
    y = 12;
  }

  return x + y;
}

f(3) === 15;
複製程式碼

Iterators 和 For-Of 迴圈

遍歷器是可以遍歷容器的物件。這是一種使類工作在for..of迴圈的有用方法。
介面類似於遍歷器介面。
迭代一個for..of迴圈的形式如下。

ES6:

// 當前環境,將從陣列中獲取一個遍歷器,並對其進行迴圈,從中獲取值
for (let element of [1, 2, 3]) {
  console.log(element);
}
// => 1 2 3
複製程式碼

ES6 (without using for-of, if Symbol is supported):

`use strict`;

for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
  var element = _step.value;
  console.log(element);
}

// => 1 2 3
複製程式碼

ES5 (approximates):

// 使用 forEach()
// 不需要在包含的範圍中宣告索引和元素變數。它們被作為引數提供給遍歷器,並被限定在遍歷的範圍內。
var a = [1,2,3];
a.forEach(function (element) {
    console.log(element);
});

// => 1 2 3

// 使用  for 迴圈
var a = [1,2,3];
for (var i = 0; i < a.length; ++i) {
    console.log(a[i]);
}
// => 1 2 3
複製程式碼

注意Symbol的使用。ES5 需要一個正確的Symbol polyfill才能正常使用。

Class

class 實現了 ES6 規範草案中描述的類語法和語義。
class 是複用程式碼最好的方法。
一些 JS 庫提供了類和繼承,但它們並不相互相容。

ES6:

class Hello {
  constructor(name) {
    this.name = name;
  }

  hello() {
    return `Hello ` + this.name + `!`;
  }

  static sayHelloAll() {
    return `Hello everyone!`;
  }
}

class HelloWorld extends Hello {
  constructor() {
    super(`World`);
  }

  echo() {
    alert(super.hello());
  }
}

var hw = new HelloWorld();
hw.echo();

alert(Hello.sayHelloAll());
複製程式碼

ES5 ( 類似功能 ):

function Hello(name) {
  this.name = name;
}

Hello.prototype.hello = function hello() {
  return `Hello ` + this.name + `!`;
};

Hello.sayHelloAll = function () {
  return `Hello everyone!`;
};

function HelloWorld() {
  Hello.call(this, `World`);
}

HelloWorld.prototype = Object.create(Hello.prototype);
HelloWorld.prototype.constructor = HelloWorld;
HelloWorld.sayHelloAll = Hello.sayHelloAll;

HelloWorld.prototype.echo = function echo() {
  alert(Hello.prototype.hello.call(this));
};

var hw = new HelloWorld();
hw.echo();

alert(Hello.sayHelloAll());
複製程式碼

更詳細的介紹可以檢視 Babel

Modules

模組功能大部分是實現了,一些載入api仍然在改進中。
模組試圖解決依賴關係和部署中的許多問題,允許使用者使用顯式匯出建立模組,從這些模組中匯入特定的匯出名稱,並保持這些名稱的獨立性。

app.js – ES6

import math from `lib/math`;
console.log(`2π = ` + math.sum(math.pi, math.pi));
複製程式碼

app.js – ES5

var math = require(`lib/math`);
console.log(`2π = ` + math.sum(math.pi, math.pi));
複製程式碼

lib/math.js – ES6

export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
複製程式碼

lib/math.js – ES5

exports.sum = sum;
function sum(x, y) {
  return x + y;
}
var pi = exports.pi = 3.141593;
複製程式碼

lib/mathplusplus.js – ES6

export * from `lib/math`;
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}
複製程式碼

lib/mathplusplus.js – ES5

var Math = require(`lib/math`);

var _extends = function (target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      target[key] = source[key];
    }
  }

  return target;
};

var e = exports.e = 2.71828182846;
exports[`default`] = function (x) {
  return Math.exp(x);
};

module.exports = _extends(exports[`default`], exports);
複製程式碼

數字字面量

ES6:

var binary = [
  0b0,
  0b1,
  0b11
];
console.assert(binary === [0, 1, 3]);

var octal = [
  0o0,
  0o1,
  0o10,
  0o77
];
console.assert(octal === [0, 1, 8, 63]);
複製程式碼

ES5:

`use strict`;

var binary = [0, 1, 3];
console.assert(binary === [0, 1, 3]);

var octal = [0, 1, 8, 63];
console.assert(octal === [0, 1, 8, 63]);
複製程式碼

屬性賦值方法

物件中支援方法語法, 比如說 toString()

ES6:

var object = {
  value: 42,
  toString() {
    return this.value;
  }
};

console.log(object.toString() === 42);
// -> true
複製程式碼

ES5:

`use strict`;

var object = {
  value: 42,
  toString: function toString() {
    return this.value;
  }
};

console.log(object.toString() === 42);
// -> true
複製程式碼

物件屬性的簡介表示

在物件中的屬性名和屬性值相同時可以忽略屬性值。

ES6:

function getPoint() {
  var x = 1;
  var y = 10;

  return {x, y};
}

console.log(getPoint() === {
  x: 1,
  y: 10
});
複製程式碼

ES5:

`use strict`;

function getPoint() {
  var x = 1;
  var y = 10;

  return { x: x, y: y };
}

console.log(getPoint() === {
  x: 1,
  y: 10
});
複製程式碼

Rest 引數

rest 引數允許函式在不使用 arguments 物件的情況下具有可變數量的引數。
rest 引數是陣列的一個例項,因此所有的陣列方法都可以使用。

ES6:

function f(x, ...y) {
  // y 是個陣列
  return x * y.length;
}

console.log(f(3, `hello`, true) === 6);
// -> true
複製程式碼

ES5:

`use strict`;

function f(x) {
  var y = [];
  y.push.apply(y, arguments) && y.shift();

  // y 是個陣列
  return x * y.length;
}

console.log(f(3, `hello`, true) === 6);
// -> true
複製程式碼

擴充套件運算子

擴充套件運算子是和 rest 引數相反的。
它允許將陣列展開為多個形式的引數。

ES6:

function add(a, b) {
  return a + b;
}

let nums = [5, 4];

console.log(add(...nums));
複製程式碼

ES5:

`use strict`;

var _toArray = function (arr) {
  return Array.isArray(arr) ? arr : [].slice.call(arr);
};

function add(a, b) {
  return a + b;
}

var nums = [5, 4];
console.log(add.apply(null, _toArray(nums)));
複製程式碼

ES6:

function f(x, y, z) {
  return x + y + z;
}
// 傳遞陣列的每一個引數
f(...[1,2,3]) === 6;
複製程式碼

ES5:

`use strict`;

function f(x, y, z) {
  return x + y + z;
}
// 傳遞陣列的每一個引數
f.apply(null, [1, 2, 3]) === 6;
複製程式碼

Proxy

ES6:

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);
console.log(p() === `I am the proxy`);
// -> true
複製程式碼

ES5:

在 ES5 中沒有 proxy, 沒有類似的方法去攔截。

類陣列

Array.from 使有著單一的引數類陣列或者列表(像:arguments, NodeList, DOMTokenList(當做classList),NamedNodeMap(屬性使用))返回一個新的陣列例項。

ES6:

var listFriends = function() {
  var friends = Array.from(arguments);
  friends.forEach(friend => {
    console.log(friend);
  });
};
listFriends(`ann`, `bob`);
// -> `ann`
// -> `bob`


var divs = document.querySelectorAll(`div`);
Array.from(divs).forEach(node => {
    console.log(node);
});
// -> <div>...</div>
// -> <div>...</div>
複製程式碼

ES5:

var listFriends = function() {
  var friends = [].slice.call(arguments)
  friends.forEach(function(friend) {
    console.log(friend);
  });
};
listFriends(`ann`, `bob`);
// -> `ann`
// -> `bob`


var divsArray = [].slice.call(document.querySelectorAll(`div`));
divsArray.forEach(function(node) {
    console.log(node);
});
// -> <div>...</div>
// -> <div>...</div>
複製程式碼

參考

重點

如果有錯誤或者錯別字,還請給我留言指出,謝謝。

我們下期見。

相關文章