簡(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)用廣泛吴叶,它往往被稱為JavaScript或JScript终息,所以它可以理解為是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è)重大更新页屠。
ES6是ECMA
為JavaScript
制定的第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目前涵蓋了ES2015、ES2016蜕企、ES2017咬荷、ES2018、ES2019轻掩、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ù)文件患亿。