ECMAScript 6

簡(jiǎn)介

ECMAScript是一種由Ecma國(guó)際(前身為歐洲計(jì)算機(jī)制造商協(xié)會(huì),European Computer Manufacturers Association)通過(guò)ECMA-262標(biāo)準(zhǔn)化的腳本程序設(shè)計(jì)語(yǔ)言诀紊。這種語(yǔ)言在萬(wàn)維網(wǎng)上應(yīng)用廣泛吴叶,它往往被稱為JavaScriptJScript终息,所以它可以理解為是JavaScript的一個(gè)標(biāo)準(zhǔn),但實(shí)際上后兩者是ECMA-262標(biāo)準(zhǔn)的實(shí)現(xiàn)和擴(kuò)展兔跌。

2015年6月亿虽, ES2015(即 ECMAScript 6涩咖、ES6) 正式發(fā)布。ES2015 是該語(yǔ)言的一個(gè)顯著更新级野,也是自 2009年 ES5 標(biāo)準(zhǔn)確定后的第一個(gè)重大更新页屠。

ES6ECMAJavaScript制定的第6個(gè)標(biāo)準(zhǔn)版本,標(biāo)準(zhǔn)委員會(huì)最終決定蓖柔,標(biāo)準(zhǔn)在每年6月正式發(fā)布并作為當(dāng)年的正式版本辰企,接下來(lái)的時(shí)間里就在此版本的基礎(chǔ)上進(jìn)行改動(dòng),直到下一年6月草案就自然變成新一年的版本况鸣,這樣一來(lái)就無(wú)需以前的版本號(hào)牢贸,只要用年份標(biāo)記即可。ECMAscript 2015是在2015年6月發(fā)布ES6的第一個(gè)版本镐捧。以此類推潜索,ECMAscript 2016是ES6的第二個(gè)版本擒滑、 ECMAscript 2017是ES6的第三個(gè)版本髓窜。ES6既是一個(gè)歷史名詞也是一個(gè)泛指钧椰,含義是5.1版本以后的JavaScript下一代標(biāo)準(zhǔn)革为,目前涵蓋了ES2015洋满、ES2016鄙漏、ES2017恃轩、ES2018脆侮、ES2019瞎领、ES2020泌辫。

所以有些文章上提到的ES7(實(shí)質(zhì)上是ES2016)、ES8(實(shí)質(zhì)上是ES2017)九默、ES9(實(shí)質(zhì)上是ES2018)震放、ES10(實(shí)質(zhì)上是ES2019)、ES11(實(shí)質(zhì)上是ES2020)荤西,實(shí)質(zhì)上都是一些不規(guī)范的概念澜搅。從ES1到ES6伍俘,每個(gè)標(biāo)準(zhǔn)都是花了好幾年甚至十多年才制定下來(lái),你一個(gè)ES6到ES7勉躺,ES7到ES8癌瘾,才用了一年,按照這樣的定義下去饵溅,那不是很快就ES20了妨退。用正確的概念來(lái)說(shuō)ES6目前涵蓋了ES2015ES2016蜕企、ES2017咬荷、ES2018ES2019轻掩、ES2020幸乒。

ECMAScript 和 JavaScript 的關(guān)系

一個(gè)常見的問(wèn)題是,ECMAScript 和 JavaScript 到底是什么關(guān)系唇牧?

要講清楚這個(gè)問(wèn)題罕扎,需要回顧歷史。1996年11月丐重,JavaScript 的創(chuàng)造者 Netscape 公司腔召,決定將 JavaScript 提交給國(guó)際標(biāo)準(zhǔn)化組織ECMA,希望這種語(yǔ)言能夠成為國(guó)際標(biāo)準(zhǔn)扮惦。次年臀蛛,ECMA 發(fā)布262號(hào)標(biāo)準(zhǔn)文件(ECMA-262)的第一版,規(guī)定了瀏覽器腳本語(yǔ)言的標(biāo)準(zhǔn)崖蜜,并將這種語(yǔ)言稱為 ECMAScript浊仆,這個(gè)版本就是1.0版。

該標(biāo)準(zhǔn)從一開始就是針對(duì) JavaScript 語(yǔ)言制定的豫领,但是之所以不叫 JavaScript氧卧,有兩個(gè)原因。一是商標(biāo)氏堤,Java 是 Sun 公司的商標(biāo),根據(jù)授權(quán)協(xié)議搏明,只有 Netscape 公司可以合法地使用 JavaScript 這個(gè)名字鼠锈,且 JavaScript 本身也已經(jīng)被 Netscape 公司注冊(cè)為商標(biāo)。二是想體現(xiàn)這門語(yǔ)言的制定者是 ECMA星著,不是 Netscape购笆,這樣有利于保證這門語(yǔ)言的開放性和中立性。

因此虚循,ECMAScript 和 JavaScript 的關(guān)系是同欠,前者是后者的規(guī)格样傍,后者是前者的一種實(shí)現(xiàn)。

ECMAScript 的歷史

ES6 從開始制定到最后發(fā)布铺遂,整整用了15年衫哥。

前面提到,ECMAScript 1.0 是1997年發(fā)布的襟锐,接下來(lái)的兩年撤逢,連續(xù)發(fā)布了 ECMAScript 2.0(1998年6月)和 ECMAScript 3.0(1999年12月)。3.0版是一個(gè)巨大的成功粮坞,在業(yè)界得到廣泛支持蚊荣,成為通行標(biāo)準(zhǔn),奠定了 JavaScript 語(yǔ)言的基本語(yǔ)法莫杈,以后的版本完全繼承互例。直到今天,初學(xué)者一開始學(xué)習(xí) JavaScript筝闹,其實(shí)就是在學(xué)3.0版的語(yǔ)法媳叨。

2000年,ECMAScript 4.0 開始醞釀丁存。這個(gè)版本最后沒有通過(guò)肩杈,但是它的大部分內(nèi)容被 ES6 繼承了。因此解寝,ES6 制定的起點(diǎn)其實(shí)是2000年扩然。

為什么 ES4 沒有通過(guò)呢?因?yàn)檫@個(gè)版本太激進(jìn)了聋伦,對(duì) ES3 做了徹底升級(jí)夫偶,導(dǎo)致標(biāo)準(zhǔn)委員會(huì)的一些成員不愿意接受。ECMA 的第39號(hào)技術(shù)專家委員會(huì)(Technical Committee 39觉增,簡(jiǎn)稱TC39)負(fù)責(zé)制訂 ECMAScript 標(biāo)準(zhǔn)兵拢,成員包括 Microsoft、Mozilla逾礁、Google 等大公司说铃。

2007年10月,ECMAScript 4.0 版草案發(fā)布嘹履,本來(lái)預(yù)計(jì)次年8月發(fā)布正式版本腻扇。但是,各方對(duì)于是否通過(guò)這個(gè)標(biāo)準(zhǔn)砾嫉,發(fā)生了嚴(yán)重分歧幼苛。以 Yahoo、Microsoft焕刮、Google 為首的大公司舶沿,反對(duì) JavaScript 的大幅升級(jí)墙杯,主張小幅改動(dòng);以 JavaScript 創(chuàng)造者Brendan Eich為首的Mozilla公司括荡,則堅(jiān)持當(dāng)前的草案高镐。

2008年7月,由于對(duì)于下一個(gè)版本應(yīng)該包括哪些功能一汽,各方分歧太大避消,爭(zhēng)論過(guò)于激烈,ECMA 開會(huì)決定召夹,中止 ECMAScript 4.0 的開發(fā)岩喷,將其中涉及現(xiàn)有功能改善的一小部分,發(fā)布為 ECMAScript 3.1监憎,而將其他激進(jìn)的設(shè)想擴(kuò)大范圍纱意,放入以后的版本,由于會(huì)議的氣氛鲸阔,該版本的項(xiàng)目代號(hào)起名為 Harmony(和諧)偷霉。會(huì)后不久,ECMAScript 3.1 就改名為 ECMAScript 5褐筛。

2009年12月类少,ECMAScript 5.0 版正式發(fā)布。Harmony 項(xiàng)目則一分為二渔扎,一些較為可行的設(shè)想定名為 JavaScript.next 繼續(xù)開發(fā)硫狞,后來(lái)演變成 ECMAScript 6;一些不是很成熟的設(shè)想晃痴,則被視為 JavaScript.next.next残吩,在更遠(yuǎn)的將來(lái)再考慮推出。TC39 委員會(huì)的總體考慮是倘核,ES5 與 ES3 基本保持兼容泣侮,較大的語(yǔ)法修正和新功能加入,將由 JavaScript.next 完成紧唱。當(dāng)時(shí)活尊,JavaScript.next 指的是ES6,第六版發(fā)布以后漏益,就指 ES7酬凳。TC39 的判斷是,ES5 會(huì)在2013年的年中成為 JavaScript 開發(fā)的主流標(biāo)準(zhǔn)遭庶,并在此后五年中一直保持這個(gè)位置。

2011年6月稠屠,ECMAscript 5.1 版發(fā)布峦睡,并且成為 ISO 國(guó)際標(biāo)準(zhǔn)(ISO/IEC 16262:2011)翎苫。

2013年3月,ECMAScript 6 草案凍結(jié)榨了,不再添加新功能煎谍。新的功能設(shè)想將被放到 ECMAScript 7。

2013年12月龙屉,ECMAScript 6 草案發(fā)布呐粘。然后是12個(gè)月的討論期,聽取各方反饋转捕。

2015年6月作岖,ECMAScript 6 正式通過(guò),成為國(guó)際標(biāo)準(zhǔn)五芝。從2000年算起痘儡,這時(shí)已經(jīng)過(guò)去了15年。

let和const命令

基本用法
ES6新增了let命令枢步,用來(lái)聲明變量沉删。它的用法類似于var,但是所聲明的變量醉途,只在let命令所在的代碼塊內(nèi)有效矾瑰。

{
  let a = 10;
  var b = 1;
}

console.log(b)  // 1
console.log(a)  // ReferenceError: a is not defined.
//demo
for (let i = 0; i < 10; i++) {}

console.log(i);
//ReferenceError: i is not defined

//ES5
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

//ES6
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

//for循環(huán)還有一個(gè)特別之處,就是循環(huán)語(yǔ)句部分是一個(gè)父作用域隘擎,而循環(huán)體內(nèi)部是一個(gè)單獨(dú)的子作用域殴穴。
for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

//不存在變量提升
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的情況
console.log(bar); // 報(bào)錯(cuò)ReferenceError
let bar = 2;

//只要塊級(jí)作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個(gè)區(qū)域嵌屎,不再受外部的影響推正。
var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

const命令

const聲明一個(gè)只讀的常量。一旦聲明宝惰,常量的值就不能改變植榕。

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

ES6 的塊級(jí)作用域

為什么需要塊級(jí)作用域?
ES5 只有全局作用域和函數(shù)作用域尼夺,沒有塊級(jí)作用域尊残,這帶來(lái)很多不合理的場(chǎng)景。

//第一種場(chǎng)景淤堵,內(nèi)層變量可能會(huì)覆蓋外層變量寝衫。
var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}
f(); // undefined

//第二種場(chǎng)景,用來(lái)計(jì)數(shù)的循環(huán)變量泄露為全局變量拐邪。
var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5

變量的解構(gòu)賦值

1.變量的解構(gòu)賦值

ES6 允許按照一定模式慰毅,從數(shù)組和對(duì)象中提取值,對(duì)變量進(jìn)行賦值扎阶,這被稱為解構(gòu)(Destructuring)汹胃。

//以前
let a = 1;
let b = 2;
let c = 3;
//es6
let [a, b, c] = [1, 2, 3];
//
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

//如果解構(gòu)不成功婶芭,變量的值就等于undefined。
let [foo] = [];
let [bar, foo] = [1];

//解構(gòu)賦值允許指定默認(rèn)值着饥。
let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b
對(duì)象的解構(gòu)賦值
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
字符串的解構(gòu)賦值
//字符串也可以解構(gòu)賦值犀农。這是因?yàn)榇藭r(shí),字符串被轉(zhuǎn)換成了一個(gè)類似數(shù)組的對(duì)象
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
//類似數(shù)組的對(duì)象都有一個(gè)length屬性宰掉,因此還可以對(duì)這個(gè)屬性解構(gòu)賦值呵哨。
let {length : len} = 'hello';
len // 5
數(shù)值和布爾值的解構(gòu)賦值
//解構(gòu)賦值時(shí),如果等號(hào)右邊是數(shù)值和布爾值轨奄,則會(huì)先轉(zhuǎn)為對(duì)象孟害。
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true
//解構(gòu)賦值的規(guī)則是,只要等號(hào)右邊的值不是對(duì)象或數(shù)組戚绕,就先將其轉(zhuǎn)為對(duì)象纹坐。由于undefined和null無(wú)法轉(zhuǎn)為對(duì)象,所以對(duì)它們進(jìn)行解構(gòu)賦值舞丛,都會(huì)報(bào)錯(cuò)耘子。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
函數(shù)參數(shù)的解構(gòu)賦值
//函數(shù)的參數(shù)也可以使用解構(gòu)賦值。
function add([x, y]){
  return x + y;
}

add([1, 2]); // 3
用途
//(1)交換變量的值
let x = 1;
let y = 2;
[x, y] = [y, x];

//(2)從函數(shù)返回多個(gè)值
// 返回一個(gè)數(shù)組

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一個(gè)對(duì)象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

//(3)函數(shù)參數(shù)的定義,解構(gòu)賦值可以方便地將一組參數(shù)與變量名對(duì)應(yīng)起來(lái)
// 參數(shù)是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 參數(shù)是一組無(wú)次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
//(4)提取 JSON 數(shù)據(jù)球切,解構(gòu)賦值對(duì)提取 JSON 對(duì)象中的數(shù)據(jù)谷誓,尤其有用。

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

//(5)函數(shù)參數(shù)的默認(rèn)值
jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

//(6)遍歷 Map 結(jié)構(gòu)
//任何部署了 Iterator 接口的對(duì)象吨凑,都可以用for...of循環(huán)遍歷捍歪。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is worl

// 7.輸入模塊的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");

字符串?dāng)U展

//字符串的遍歷器接口
for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"

//模板字符串
//傳統(tǒng)
$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);
//es6
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);
//大括號(hào)內(nèi)部可以放入任意的 JavaScript 表達(dá)式,可以進(jìn)行運(yùn)算鸵钝,以及引用對(duì)象屬性糙臼。
let x = 1;
let y = 2;

`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"

`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"

//模板字符串之中還能調(diào)用函數(shù)
function fn() {
  return "Hello World";
}

`foo ${fn()} bar`
// foo Hello World bar

字符串新增方法

//傳統(tǒng)上,JavaScript 只有indexOf方法恩商,可以用來(lái)確定一個(gè)字符串是否包含在另一個(gè)字符串中变逃。ES6 又提供了三種新方法。

// -- includes():返回布爾值怠堪,表示是否找到了參數(shù)字符串揽乱。
// --  startsWith():返回布爾值,表示參數(shù)字符串是否在原字符串的頭部粟矿。
// -- endsWith():返回布爾值凰棉,表示參數(shù)字符串是否在原字符串的尾部。
let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

//這三個(gè)方法都支持第二個(gè)參數(shù)陌粹,表示開始搜索的位置撒犀。
let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
//使用第二個(gè)參數(shù)n時(shí),endsWith的行為與其他兩個(gè)方法有所不同。它針對(duì)前n個(gè)字符或舞,而其他兩個(gè)方法針對(duì)從第n個(gè)位置直到字符串結(jié)束

//repeat方法返回一個(gè)新字符串隧膏,表示將原字符串重復(fù)n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

//padStart()嚷那,padEnd(),ES2017 引入了字符串補(bǔ)全長(zhǎng)度的功能。如果某個(gè)字符串不夠指定長(zhǎng)度杆煞,會(huì)在頭部或尾部補(bǔ)全魏宽。padStart()用于頭部補(bǔ)全,padEnd()用于尾部補(bǔ)全
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
//上面代碼中决乎,padStart()和padEnd()一共接受兩個(gè)參數(shù)队询,第一個(gè)參數(shù)是字符串補(bǔ)全生效的最大長(zhǎng)度,第二個(gè)參數(shù)是用來(lái)補(bǔ)全的字符串构诚。
//如果原字符串的長(zhǎng)度蚌斩,等于或大于最大長(zhǎng)度,則字符串補(bǔ)全不生效范嘱,返回原字符串

//ES2019對(duì)字符串實(shí)例新增了trimStart()送膳,trimEnd()
const s = '  abc  ';

s.trim() // "abc"
s.trimStart() // "abc  "
s.trimEnd() // "  abc"
// trimLeft()是trimStart()的別名,trimRight()是trimEnd()的別名丑蛤。

數(shù)組的擴(kuò)展

1.擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符(spread)是三個(gè)點(diǎn)(...)叠聋。它好比 rest 參數(shù)的逆運(yùn)算,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列受裹。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.querySelectorAll('div')]

//該運(yùn)算符主要用于函數(shù)調(diào)用
function push(array, ...items) {
  array.push(...items);
}

function add(x, y) {
  return x + y;
}

const numbers = [4, 38];
add(...numbers) // 42

//替代函數(shù)的 apply 方法
// ES5 的寫法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f.apply(null, args);

// ES6的寫法
function f(x, y, z) {
  // ...
}
let args = [0, 1, 2];
f(...args);

擴(kuò)展運(yùn)算符的應(yīng)用
復(fù)制數(shù)組
數(shù)組是復(fù)合的數(shù)據(jù)類型碌补,直接復(fù)制的話,只是復(fù)制了指向底層數(shù)據(jù)結(jié)構(gòu)的指針棉饶,而不是克隆一個(gè)全新的數(shù)組厦章。

const a1 = [1, 2];
const a2 = a1;

a2[0] = 2;
a1 // [2, 2]

//ES5 只能用變通方法來(lái)復(fù)制數(shù)組
const a1 = [1, 2];
const a2 = a1.concat();

a2[0] = 2;
a1 // [1, 2]

//擴(kuò)展運(yùn)算符提供了復(fù)制數(shù)組的簡(jiǎn)便寫法
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;

合并數(shù)組
擴(kuò)展運(yùn)算符提供了數(shù)組合并的新寫法

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并數(shù)組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并數(shù)組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true
//淺拷貝。如果修改了引用指向的值照藻,會(huì)同步反映到新數(shù)組

2.數(shù)組實(shí)例的 find() 和 findIndex()
數(shù)組實(shí)例的find方法袜啃,用于找出第一個(gè)符合條件的數(shù)組成員。它的參數(shù)是一個(gè)回調(diào)函數(shù)岩梳,所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù)囊骤,直到找出第一個(gè)返回值為true的成員,然后返回該成員冀值。如果沒有符合條件的成員也物,則返回undefined。

[1, 4, -5, 10].find((n) => n < 0)
// -5

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

function f(v){
  return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);    // 26

3.數(shù)組實(shí)例的 includes()
Array.prototype.includes方法返回一個(gè)布爾值列疗,表示某個(gè)數(shù)組是否包含給定的值滑蚯,與字符串的includes方法類似。ES2016 引入了該方法。

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

4.Array.of()
Array.of方法用于將一組值告材,轉(zhuǎn)換為數(shù)組坤次。

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

對(duì)象的擴(kuò)展

1.屬性的簡(jiǎn)潔表示法
ES6 允許在大括號(hào)里面,直接寫入變量和函數(shù)斥赋,作為對(duì)象的屬性和方法缰猴。這樣的書寫更加簡(jiǎn)潔。

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}

// 等同于
const baz = {foo: foo};

function f(x, y) {
  return {x, y};
}

// 等同于

function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

let birth = '2000/01/01';

const Person = {

  name: '張三',

  //等同于birth: birth
  birth,

  // 等同于hello: function ()...
  hello() { console.log('我的名字是', this.name); }

};

2.屬性名表達(dá)式

var obj = {
  foo: true,
  abc: 123
};

let propKey = 'foo';

let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
};
console.log(obj.foo) // true

super 關(guān)鍵字
我們知道疤剑,this關(guān)鍵字總是指向函數(shù)所在的當(dāng)前對(duì)象滑绒,ES6 又新增了另一個(gè)類似的關(guān)鍵字super,指向當(dāng)前對(duì)象的原型對(duì)象隘膘。

const proto = {
  foo: 'hello'
};

const obj = {
  foo: 'world',
  find() {
    return super.foo;
  }
};

Object.setPrototypeOf(obj, proto);
obj.find() // "hello"

上面代碼中疑故,對(duì)象obj.find()方法之中,通過(guò)super.foo引用了原型對(duì)象proto的foo屬性弯菊。

注意纵势,super關(guān)鍵字表示原型對(duì)象時(shí),只能用在對(duì)象的方法之中管钳,用在其他地方都會(huì)報(bào)錯(cuò)钦铁。

// 報(bào)錯(cuò)
const obj = {
  foo: super.foo
}

// 報(bào)錯(cuò)
const obj = {
  foo: () => super.foo
}

// 報(bào)錯(cuò)
const obj = {
  foo: function () {
    return super.foo
  }
}

上面三種super的用法都會(huì)報(bào)錯(cuò),因?yàn)閷?duì)于 JavaScript 引擎來(lái)說(shuō)蹋嵌,這里的super都沒有用在對(duì)象的方法之中育瓜。第一種寫法是super用在屬性里面,第二種和第三種寫法是super用在一個(gè)函數(shù)里面栽烂,然后賦值給foo屬性躏仇。目前,只有對(duì)象方法的簡(jiǎn)寫法可以讓 JavaScript 引擎確認(rèn)腺办,定義的是對(duì)象的方法焰手。

JavaScript 引擎內(nèi)部,super.foo等同于Object.getPrototypeOf(this).foo(屬性)或Object.getPrototypeOf(this).foo.call(this)(方法)怀喉。

const proto = {
  x: 'hello',
  foo() {
    console.log(this.x);
  },
};

const obj = {
  x: 'world',
  foo() {
    super.foo();
  }
}

Object.setPrototypeOf(obj, proto);

obj.foo() // "world"

上面代碼中书妻,super.foo指向原型對(duì)象proto的foo方法,但是綁定的this卻還是當(dāng)前對(duì)象obj躬拢,因此輸出的就是world躲履。

對(duì)象的擴(kuò)展運(yùn)算符
ES2018 將這個(gè)運(yùn)算符引入了對(duì)象。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

//擴(kuò)展運(yùn)算符可以用于合并兩個(gè)對(duì)象聊闯。
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);

對(duì)象新增方法

1.Object.is()
ES5 比較兩個(gè)值是否相等工猜,只有兩個(gè)運(yùn)算符:相等運(yùn)算符(==)和嚴(yán)格相等運(yùn)算符(===)。它們都有缺點(diǎn)菱蔬,前者會(huì)自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型篷帅,后者的NaN不等于自身史侣,以及+0等于-0。JavaScript 缺乏一種運(yùn)算魏身,在所有環(huán)境中惊橱,只要兩個(gè)值是一樣的,它們就應(yīng)該相等箭昵。

ES6 提出“Same-value equality”(同值相等)算法税朴,用來(lái)解決這個(gè)問(wèn)題。Object.is就是部署這個(gè)算法的新方法家制。它用來(lái)比較兩個(gè)值是否嚴(yán)格相等掉房,與嚴(yán)格比較運(yùn)算符(===)的行為基本一致。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

不同之處只有兩個(gè):一是+0不等于-0慰丛,二是NaN等于自身。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

2.Object.assign()
Object.assign方法用于對(duì)象的合并瘾杭,將源對(duì)象(source)的所有可枚舉屬性诅病,復(fù)制到目標(biāo)對(duì)象(target)。

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意點(diǎn)
(1)淺拷貝
Object.assign方法實(shí)行的是淺拷貝粥烁,而不是深拷貝贤笆。也就是說(shuō),如果源對(duì)象某個(gè)屬性的值是對(duì)象讨阻,那么目標(biāo)對(duì)象拷貝得到的是這個(gè)對(duì)象的引用芥永。

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

(2)同名屬性的替換
對(duì)于這種嵌套的對(duì)象,一旦遇到同名屬性钝吮,Object.assign的處理方法是替換埋涧,而不是添加。

const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }

Object.assign常見用途
1)為對(duì)象添加屬性

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}

2)為對(duì)象添加方法

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    ···
  },
  anotherMethod() {
    ···
  }
});

// 等同于下面的寫法
SomeClass.prototype.someMethod = function (arg1, arg2) {
  ···
};
SomeClass.prototype.anotherMethod = function () {
  ···
};

3)克隆對(duì)象

function clone(origin) {
  return Object.assign({}, origin);
}

函數(shù)的擴(kuò)展-箭頭函數(shù)

ES6 允許使用“箭頭”(=>)定義函數(shù)奇瘦。

var f = v => v;

// 等同于
var f = function (v) {
  return v;
};

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

不適用場(chǎng)合
由于箭頭函數(shù)使得this從“動(dòng)態(tài)”變成“靜態(tài)”棘催,下面兩個(gè)場(chǎng)合不應(yīng)該使用箭頭函數(shù)。

第一個(gè)場(chǎng)合是定義對(duì)象的方法耳标,且該方法內(nèi)部包括this醇坝。

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

第二個(gè)場(chǎng)合是需要?jiǎng)討B(tài)this的時(shí)候,也不應(yīng)使用箭頭函數(shù)

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

Promise 對(duì)象次坡、async 函數(shù)

Promise 的含義

Promise 是異步編程的一種解決方案呼猪,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。它由社區(qū)最早提出和實(shí)現(xiàn)砸琅,ES6 將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn)宋距,統(tǒng)一了用法,原生提供了Promise對(duì)象明棍。

所謂Promise乡革,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō)沸版,Promise 是一個(gè)對(duì)象嘁傀,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API视粮,各種異步操作都可以用同樣的方法進(jìn)行處理细办。

Promise對(duì)象有以下兩個(gè)特點(diǎn)。

(1)對(duì)象的狀態(tài)不受外界影響蕾殴。Promise對(duì)象代表一個(gè)異步操作笑撞,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失數鼍酢)茴肥。只有異步操作的結(jié)果,可以決定當(dāng)前是哪一種狀態(tài)荡灾,任何其他操作都無(wú)法改變這個(gè)狀態(tài)瓤狐。這也是Promise這個(gè)名字的由來(lái),它的英語(yǔ)意思就是“承諾”批幌,表示其他手段無(wú)法改變础锐。

(2)一旦狀態(tài)改變,就不會(huì)再變荧缘,任何時(shí)候都可以得到這個(gè)結(jié)果皆警。Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected截粗。只要這兩種情況發(fā)生信姓,狀態(tài)就凝固了,不會(huì)再變了绸罗,會(huì)一直保持這個(gè)結(jié)果财破,這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了从诲,你再對(duì)Promise對(duì)象添加回調(diào)函數(shù)左痢,也會(huì)立即得到這個(gè)結(jié)果。這與事件(Event)完全不同系洛,事件的特點(diǎn)是俊性,如果你錯(cuò)過(guò)了它,再去監(jiān)聽描扯,是得不到結(jié)果的定页。

有了Promise對(duì)象,就可以將異步操作以同步操作的流程表達(dá)出來(lái)绽诚,避免了層層嵌套的回調(diào)函數(shù)典徊。此外杭煎,Promise對(duì)象提供統(tǒng)一的接口,使得控制異步操作更加容易卒落。

Promise也有一些缺點(diǎn)羡铲。首先,無(wú)法取消Promise儡毕,一旦新建它就會(huì)立即執(zhí)行也切,無(wú)法中途取消。其次腰湾,如果不設(shè)置回調(diào)函數(shù)雷恃,Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部费坊。第三倒槐,當(dāng)處于pending狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)附井。

基本用法

ES6 規(guī)定导犹,Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成Promise實(shí)例羡忘。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject磕昼。它們是兩個(gè)函數(shù)卷雕,由 JavaScript 引擎提供,不用自己部署票从。

resolve函數(shù)的作用是漫雕,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用峰鄙,并將異步操作的結(jié)果浸间,作為參數(shù)傳遞出去;reject函數(shù)的作用是吟榴,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected)魁蒜,在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤吩翻,作為參數(shù)傳遞出去兜看。

Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)狭瞎。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)细移。第一個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用熊锭。其中弧轧,第二個(gè)函數(shù)是可選的雪侥,不一定要提供。這兩個(gè)函數(shù)都接受Promise對(duì)象傳出的值作為參數(shù)精绎。

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

Promise 新建后就會(huì)立即執(zhí)行速缨。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

Promise 新建后立即執(zhí)行,所以首先輸出的是Promise捺典。然后鸟廓,then方法指定的回調(diào)函數(shù),將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會(huì)執(zhí)行襟己,所以resolved最后輸出引谜。
Promise.prototype.then()
Promise 實(shí)例具有then方法,也就是說(shuō)擎浴,then方法是定義在原型對(duì)象Promise.prototype上的员咽。它的作用是為 Promise 實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)。前面說(shuō)過(guò)贮预,then方法的第一個(gè)參數(shù)是resolved狀態(tài)的回調(diào)函數(shù)贝室,第二個(gè)參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)。

then方法返回的是一個(gè)新的Promise實(shí)例(注意仿吞,不是原來(lái)那個(gè)Promise實(shí)例)滑频。因此可以采用鏈?zhǔn)綄懛ǎ磘hen方法后面再調(diào)用另一個(gè)then方法唤冈。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯(cuò)了', error);
});

Promise 實(shí)例具有then方法峡迷,也就是說(shuō),then方法是定義在原型對(duì)象Promise.prototype上的你虹。它的作用是為 Promise 實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)绘搞。前面說(shuō)過(guò),then方法的第一個(gè)參數(shù)是resolved狀態(tài)的回調(diào)函數(shù)傅物,第二個(gè)參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)夯辖。

then方法返回的是一個(gè)新的Promise實(shí)例(注意,不是原來(lái)那個(gè)Promise實(shí)例)董饰。因此可以采用鏈?zhǔn)綄懛ㄝ锕樱磘hen方法后面再調(diào)用另一個(gè)then方法。

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面的代碼使用then方法卒暂,依次指定了兩個(gè)回調(diào)函數(shù)贮缅。第一個(gè)回調(diào)函數(shù)完成以后,會(huì)將返回結(jié)果作為參數(shù)介却,傳入第二個(gè)回調(diào)函數(shù)谴供。

采用鏈?zhǔn)降膖hen,可以指定一組按照次序調(diào)用的回調(diào)函數(shù)齿坷。這時(shí)桂肌,前一個(gè)回調(diào)函數(shù)数焊,有可能返回的還是一個(gè)Promise對(duì)象(即有異步操作),這時(shí)后一個(gè)回調(diào)函數(shù)崎场,就會(huì)等待該P(yáng)romise對(duì)象的狀態(tài)發(fā)生變化佩耳,才會(huì)被調(diào)用。

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function (comments) {
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

Promise.prototype.catch()
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的別名谭跨,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)干厚。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 處理 getJSON 和 前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤
  console.log('發(fā)生錯(cuò)誤!', error);
});

Promise.prototype.finally()
finally()方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何螃宙,都會(huì)執(zhí)行的操作蛮瞄。該方法是 ES2018 引入標(biāo)準(zhǔn)的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

Promise.all()
Promise.all()方法用于將多個(gè) Promise 實(shí)例谆扎,包裝成一個(gè)新的 Promise 實(shí)例挂捅。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(`錯(cuò)誤${url}`);
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  console.log(posts)
}).catch(function(reason){
  console.log(reason)
});

promises是包含 6 個(gè) Promise 實(shí)例的數(shù)組,只有這 6 個(gè)實(shí)例的狀態(tài)都變成fulfilled堂湖,或者其中有一個(gè)變?yōu)閞ejected闲先,才會(huì)調(diào)用Promise.all方法后面的回調(diào)函數(shù)。

async

ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù)无蜂,使得異步操作變得更加方便伺糠。

async 函數(shù)是什么?一句話斥季,它就是 Generator 函數(shù)的語(yǔ)法糖训桶。

前文有一個(gè) Generator 函數(shù),依次讀取兩個(gè)文件泻肯。

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

上面代碼的函數(shù)gen可以寫成async函數(shù),就是下面這樣慰照。

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

async函數(shù)返回一個(gè) Promise 對(duì)象灶挟,可以使用then方法添加回調(diào)函數(shù)。當(dāng)函數(shù)執(zhí)行的時(shí)候毒租,一旦遇到await就會(huì)先返回稚铣,等到異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語(yǔ)句墅垮。

function takeLongTime() {
    return new Promise(resolve => {
        setTimeout(() => resolve("long_time_value"), 1000);
    });
}

async function test() {
    const v = await takeLongTime();
    console.log(v);
}

返回 Promise 對(duì)象

async函數(shù)返回一個(gè) Promise 對(duì)象惕医。

async函數(shù)內(nèi)部return語(yǔ)句返回的值,會(huì)成為then方法回調(diào)函數(shù)的參數(shù)算色。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

Class 類

類的由來(lái)

JavaScript 語(yǔ)言中抬伺,生成實(shí)例對(duì)象的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)。下面是一個(gè)例子灾梦。

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

S6 提供了更接近傳統(tǒng)語(yǔ)言的寫法峡钓,引入了 Class(類)這個(gè)概念妓笙,作為對(duì)象的模板昌渤。通過(guò)class關(guān)鍵字旷赖,可以定義類。

基本上崇摄,ES6 的class可以看作只是一個(gè)語(yǔ)法糖拉鹃,它的絕大部分功能辈赋,ES5 都可以做到,新的class寫法只是讓對(duì)象原型的寫法更加清晰膏燕、更像面向?qū)ο缶幊痰恼Z(yǔ)法而已钥屈。上面的代碼用 ES6 的class改寫,就是下面這樣煌寇。

function Person1(name, age) {
  this.name = name
  this.age = age
}
Person1.prototype.say = function () {
  return "My name is " + this.name + ", I'm " + this.age + " years old."
}
var obj = new Person1("Simon", 28);
console.log(obj.say()); // My name is Simon, I'm 28 years old.

//es6
class Person2 {
  // 用constructor構(gòu)造方法接收參數(shù)
  constructor(name, age) {
    this.name = name; // this代表的是實(shí)例對(duì)象
    this.age = age;
  }
  // 類的方法焕蹄,此處不能加function
  say() {
    return "My name is " + this.name + ", I'm " + this.age + " years old."
  }
}
var obj = new Person2("Coco", 26);
console.log(obj.say()); // My name is Coco, I'm 26 years old.

類的繼承

Class 可以通過(guò)extends關(guān)鍵字實(shí)現(xiàn)繼承,這比 ES5 的通過(guò)修改原型鏈實(shí)現(xiàn)繼承阀溶,要清晰和方便很多腻脏。

/**
 * es5:class 對(duì)象
 */

function Car(option) {
  this.title = option.title;
  this.lunz = option.lunz;
}

Car.prototype.drive = function () {
  return this.title + " is drive..";
}

const car = new Car({ title: "bmw", lunz: "more than 3." });
console.log(car);
console.log(car.drive());

/**
 * es5:繼承
 */

function KIA(option) {
  Car.call(this, option);
  this.color = option.color;
}

KIA.prototype = Object.create(Car.prototype);
KIA.prototype.constructor = KIA;

KIA.prototype.drive = function () {
  return this.title + " is drive, its color is " + this.color;
}

const kia = new KIA({ color: "white", title: "kia", lunz: 'more than 4.' });
console.log(kia.drive());


上面代碼定義了一個(gè)ColorPoint類,該類通過(guò)extends關(guān)鍵字银锻,繼承了Point類的所有屬性和方法永品。但是由于沒有部署任何代碼,所以這兩個(gè)類完全一樣击纬,等于復(fù)制了一個(gè)Point類鼎姐。下面,我們?cè)贑olorPoint內(nèi)部加上代碼更振。

class book{
    constructor(){
        this._year=2004;
        this.edition=1;
    }
    get year(){
        return this._year;
    }
    set year(newVal){
        if(newVal>2004){
            this._year=newVal;
            this.edition+=newVal-2004;
        }
    }
}
let b=new book();
b.year = 2004; //2
console.log(b.edition);

/**
 * es6 class+繼承(extends + super)
 */
class CarES6 {
  constructor({ title, lunz }) {
    this.title = title;
    this.lunz = lunz;
  }
  drive() {
    return this.title + " is drive.. (es6)";
  }
}

const carNew = new CarES6({ title: "bmw", lunz: "more than 3." });
console.log(carNew);

class KIAES6 extends CarES6 {
  constructor(options) {
    super(options);
    this.color = options.color;
  }
}

const kiaNew = new KIAES6({ color: "white", title: "kia", lunz: 'more than 4.' });
console.log(kiaNew);

constructor方法和toString方法之中炕桨,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù)肯腕,用來(lái)新建父類的this對(duì)象献宫。

子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)实撒。這是因?yàn)樽宇愖约旱膖his對(duì)象姊途,必須先通過(guò)父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實(shí)例屬性和方法知态,然后再對(duì)其進(jìn)行加工捷兰,加上子類自己的實(shí)例屬性和方法。如果不調(diào)用super方法负敏,子類就得不到this對(duì)象贡茅。

Module

歷史上,JavaScript 一直沒有模塊(module)體系其做,無(wú)法將一個(gè)大程序拆分成互相依賴的小文件友扰,再用簡(jiǎn)單的方法拼裝起來(lái)彤叉。其他語(yǔ)言都有這項(xiàng)功能,比如 Ruby 的require村怪、Python 的import秽浇,甚至就連 CSS 都有@import,但是 JavaScript 任何這方面的支持都沒有甚负,這對(duì)開發(fā)大型的柬焕、復(fù)雜的項(xiàng)目形成了巨大障礙。

在 ES6 之前梭域,社區(qū)制定了一些模塊加載方案斑举,最主要的有 CommonJS 和 AMD 兩種。前者用于服務(wù)器病涨,后者用于瀏覽器富玷。ES6 在語(yǔ)言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能既穆,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單赎懦,完全可以取代 CommonJS 和 AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案幻工。

ES6 模塊的設(shè)計(jì)思想是盡量的靜態(tài)化励两,使得編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量囊颅。CommonJS 和 AMD 模塊当悔,都只能在運(yùn)行時(shí)確定這些東西。比如踢代,CommonJS 模塊就是對(duì)象盲憎,輸入時(shí)必須查找對(duì)象屬性。

// CommonJS模塊
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
// ES6模塊
import { stat, exists, readFile } from 'fs';

兼容情況

ES6 提供了許多新特性胳挎,但并不是所有的瀏覽器都能夠完美支持饼疙。好在目前各大瀏覽器自身也加快速度兼容 ES6 的新特性,其中對(duì) ES6 新特性最友好的是 Chrome 和 Firefox 瀏覽器串远。

一宏多、桌面端瀏覽器對(duì)ES2015的支持情況

  • Chrome:51 版起便可以支持 97% 的 ES6 新特性儿惫。
  • Firefox:53 版起便可以支持 97% 的 ES6 新特性澡罚。
  • Safari:10 版起便可以支持 99% 的 ES6 新特性。
  • IE:Edge 15可以支持 96% 的 ES6 新特性肾请。Edge 14 可以支持 93% 的 ES6 新特性留搔。(IE7~11 基本不支持 ES6)

二、移動(dòng)端瀏覽器對(duì)ES2015的支持情況

  • iOS:10.0 版起便可以支持 99% 的 ES6 新特性铛铁。
  • Android:基本不支持 ES6 新特性(5.1 僅支持 25%)

三隔显、服務(wù)器對(duì)ES2015的支持情況
Node.js:6.5 版起便可以支持 97% 的 ES6 新特性却妨。(6.0 支持 92%)

附:如何使用ES6的新特性,又能保證瀏覽器的兼容括眠?
針對(duì) ES6 的兼容性問(wèn)題彪标,很多團(tuán)隊(duì)為此開發(fā)出了多種語(yǔ)法解析轉(zhuǎn)換工具,把我們寫的 ES6 語(yǔ)法轉(zhuǎn)換成 ES5掷豺,相當(dāng)于在 ES6 和瀏覽器之間做了一個(gè)翻譯官捞烟。比較通用的工具方案有 babel,jsx当船,traceur题画,es6-shim 等。

babel

babel主要用于編譯JavaScript代碼德频。一般來(lái)說(shuō)苍息,我們使用JavaScript的最新語(yǔ)法特性來(lái)編寫程序,但為了能夠兼容更多的瀏覽器壹置,會(huì)使用babel將兼容性不好的語(yǔ)法特性編譯成被各個(gè)瀏覽器廣泛支持的形式竞思。

Traceur 轉(zhuǎn)碼器

Google 公司的Traceur轉(zhuǎn)碼器,也可以將 ES6 代碼轉(zhuǎn)為 ES5 代碼蒸绩。

直接插入網(wǎng)頁(yè)

Traceur 允許將 ES6 代碼直接插入網(wǎng)頁(yè)衙四。首先,必須在網(wǎng)頁(yè)頭部加載 Traceur 庫(kù)文件患亿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末传蹈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子步藕,更是在濱河造成了極大的恐慌惦界,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咙冗,死亡現(xiàn)場(chǎng)離奇詭異沾歪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)雾消,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門灾搏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人立润,你說(shuō)我怎么就攤上這事狂窑。” “怎么了桑腮?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵泉哈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)丛晦,這世上最難降的妖魔是什么奕纫? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮烫沙,結(jié)果婚禮上匹层,老公的妹妹穿的比我還像新娘。我一直安慰自己锌蓄,他們只是感情好又固,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著煤率,像睡著了一般仰冠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝶糯,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天洋只,我揣著相機(jī)與錄音,去河邊找鬼昼捍。 笑死识虚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妒茬。 我是一名探鬼主播担锤,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乍钻!你這毒婦竟也來(lái)了肛循?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤银择,失蹤者是張志新(化名)和其女友劉穎多糠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浩考,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夹孔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了析孽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搭伤。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖袜瞬,靈堂內(nèi)的尸體忽然破棺而出怜俐,到底是詐尸還是另有隱情,我是刑警寧澤吞滞,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布佑菩,位于F島的核電站,受9級(jí)特大地震影響裁赠,放射性物質(zhì)發(fā)生泄漏殿漠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一佩捞、第九天 我趴在偏房一處隱蔽的房頂上張望绞幌。 院中可真熱鬧,春花似錦一忱、人聲如沸莲蜘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)票渠。三九已至,卻和暖如春芬迄,著一層夾襖步出監(jiān)牢的瞬間问顷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工禀梳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杜窄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓算途,卻偏偏與公主長(zhǎng)得像塞耕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘴瓤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容