ECMAScript和JavaScript的關係是,前者是後者的規格,後者是前者的一種實現
初學者一開始學習JavaScript,其實就是在學3.0版的語法。
----------------------------------------------------
Node.js是JavaScript語言的服務器運行環境,對ES6的支持度比瀏覽器更高。經過Node,能夠體驗更多ES6的特性。建議使用版
本管理工具nvm,來安裝Node,由於能夠自由切換版本。不過, nvm 不支持Windows系統,若是你使用Windows系統,下面的
操做能夠改用nvmw或nvm-windows代替。
----------------------------------------------------java
ES6新增了 let 命令,用來聲明變量。它的用法相似於 var ,可是所聲明的變量,只在 let 命令所在的代碼塊內有效es6
let 不像 var 那樣會發生「變量提高」現象。因此,變量必定要在聲明後使用,不然報錯。算法
只要塊級做用域內存在 let 命令,它所聲明的變量就「綁定」(binding)這個區域,ES6明確規定,若是區塊中存在 let 和 const 命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是
在聲明以前就使用這些變量,就會報錯。編程
爲何須要塊級做用域?ES5只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景
第一種場景,內層變量可能會覆蓋外層變量
第二種場景,用來計數的循環變量泄露爲全局變量。
let 實際上爲JavaScript新增了塊級做用域json
ES5存在函數提高,無論會
不會進入 if 代碼塊,函數聲明都會提高到當前做用域的頂部,獲得執行
而ES6支持塊級做用域,無論會不會進入if代碼
塊,其內部聲明的函數皆不會影響到做用域的外部。
-------------------------------------------------
const 聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
const聲明的變量不得改變值,這意味着,const一旦聲明變量,就必須當即初始化,不能留到之後賦值。
const的做用域與let命令相同:只在聲明所在的塊級做用域內有效,也是不提高,存在暫時性死區,不可重複聲明
對於複合類型的變量(對象),變量名不指向數據,而是指向數據所在的地址,不可變的只是這個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性
------------------------------------------------------------
ES5只有兩種聲明變量的方法: var 命令和 function 命令。ES6除了添加 let 和 const 命令另外
兩種聲明變量的方法: import 命令和 class 命令。因此,ES6一共有6種聲明變量的方法。
------------------------------------------------------------
全局對象是最頂層的對象,在瀏覽器環境指的是 window 對象,在Node.js指的是 global 對象
var 命令和 function 命令聲明的全局變量,依舊是全局對象的屬性;另外一方面規定,let 命令、 const 命令、 class 命令聲明的全局變量,不屬於全局對象的屬性。
------------------------------------------------------------
數組解構的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者。windows
解構賦值的規則是,只要等號右邊的值不是對象,就先將其轉爲對象,因爲 undefined 和 null 沒法轉爲對象,因此對它們
進行解構賦值,都會報錯。數組
avaScript內部,字符以UTF-16的格式儲存,每一個字符固定爲2個字節,對於那些須要4個字節儲存的字符(Unicode碼點大於
0xFFFF的字符),JavaScript會認爲它們是兩個字符。
--------------------------------------------------------------
JavaScript只有 indexOf 方法,能夠用來肯定一個字符串是否包含在另外一個字符串中,ES6又提供了三種新方法
includes():返回布爾值,表示是否找到了參數字符串
startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部
endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部
這三個方法都支持第二個參數,表示開始搜索的位置
--------------------------------------------------------------
repeat 方法返回一個新字符串,表示將原字符串重複 n 次
padStart 和 padEnd 字符串補全長度的功能,一共接受兩個參數,第一個參數用來指定字符串的最小長度,第二個參數是用來補全的
字符串。
--------------------------------------------------------------
模板字符串(template string)是加強版的字符串,用反引號(`)標識。它能夠看成普通字符串使用,也能夠用來定義多行字符
串,或者在字符串中嵌入變量。模板字符串中嵌入變量,須要將變量名寫在 ${} 之中。
${}若是大括號中的值不是字符串,將按照通常的規則轉爲字符串。好比,大括號中是一個對象,將默認調用對象的 toString 方
法。大括號內部,就是執行JavaScript代碼,所以若是大括號內部是一個字符串,將會原樣輸出promise
ES6還爲原生的String對象,提供了一個 raw 方法。String.raw 方法,每每用來充當模板字符串的處理函數,返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串,對
應於替換變量後的模板字符串。
--------------------------------------------------------------
Number.isFinite()用來檢查一個數值是否爲有限的(finite),即不是Infinity。
Number.isNaN()用來檢查一個值是否爲NaN。
Number.isFinite()對於非數值一概返回false, Number.isNaN()只有對於NaN才返回true,非NaN一概返回false。
ES6 將全局方法parseInt()和parseFloat(),移植到Number對象上面
Number.isInteger()用來判斷一個數值是否爲整數。
Math.trunc方法用於去除一個數的小數部分,返回整數部分。
Math.sign方法用來判斷一個數究竟是正數、負數、仍是零。對於非數值,會先將其轉換爲數值。
它會返回五種值。瀏覽器
這是由於length屬性的含義是,該函數預期傳入的參數個數。某個參數指定默認值之後,預期傳入的參數個數就不包括這個參數了。若是設置了默認值的參數不是尾參數,那麼length屬性也再也不計入後面的參數了。緩存
一旦設置了參數的默認值,函數進行聲明初始化時,參數會造成一個單獨的做用域
ES6 引入 rest
參數(形式爲...變量名),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。
注意,rest 參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。函數的length屬性,不包括 rest 參數
--------------------------------------------------------------
擴展運算符(spread)是三個點(...)。它比如 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。容易和rest混淆,兩個不是一個東西。
function f(v, w, x, y, z) { } const args = [0, 1]; f(-1, ...args, 2, ...[3]);
1.因爲擴展運算符能夠展開數組,因此再也不須要apply方法,將數組轉爲函數的參數了。
2.數組是複合的數據類型,直接複製的話,只是複製了指向底層數據結構的指針,而不是克隆一個全新的數組。擴展運算符提供了複製數組的簡便寫法。
const a1 = [1, 2]; // 寫法一 const a2 = [...a1]; // 寫法二 const [...a2] = a1; 3.合併數組 // ES5 [1, 2].concat(more) // ES6 [1, 2, ...more]
4.擴展運算符能夠與解構賦值結合起來,用於生成數組。若是將擴展運算符用於數組賦值,只能放在參數的最後一位,不然會報錯。
const [...butLast, last] = [1, 2, 3, 4, 5];
// 報錯
5.擴展運算符還能夠將字符串轉爲真正的數組。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
Array.from方法用於將兩類對象轉爲真正的數組,擴展運算符背後調用的是遍歷器接口(Symbol.iterator),若是一個對象沒有部署這個接口,就沒法轉換。Array.from方法還支持相似數組的對象。所謂相似數組的對象,本質特徵只有一點,即必須有length屬性。所以,任何有length屬性的對象,均可以經過Array.from方法轉爲數組,而此時擴展運算符就沒法轉換。
Array.of方法用於將一組值,轉換爲數組。
Array.of(3, 11, 8) // [3,11,8]
Array.of基本上能夠用來替代Array()或new Array(),而且不存在因爲參數不一樣而致使的重載。它的行爲很是統一。
--------------------------------------------------------------
數組實例的copyWithin方法,在當前數組內部,將指定位置的成員複製到其餘位置(會覆蓋原有成員),而後返回當前數組。也就是說,使用這個方法,會修改當前數組。
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
數組實例的 find() 和 findIndex()
[1, 4, -5, 10].find((n) => n < 0) // -5
數組實例的findIndex方法的用法與find方法很是相似,返回第一個符合條件的數組成員的位置,若是全部成員都不符合條件,則返回-1。
這兩個方法均可以發現NaN,彌補了數組的indexOf方法的不足。
--------------------------------------------------------------
數組實例的 includes(),沒有該方法以前,咱們一般使用數組的indexOf方法,檢查是否包含某個值。indexOf方法有兩個缺點,一是不夠語義化,它的含義是找到參數值的第一個出現位置,因此要去比較是否不等於-1,表達起來不夠直觀。二是,它內部使用嚴格相等運算符(===)進行判斷,這會致使對NaN的誤判。
Object.assign方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target)。Object.assign拷貝的屬性是有限制的,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)。
注意點(1)淺拷貝(2)同名屬性的替換(3)數組的處理(4)取值函數的處理
常見用途(1)爲對象添加屬性(2)爲對象添加方法(3)克隆對象(4)合併多個對象(5)爲屬性指定默認值
--------------------------------------------------------------
對象的每一個屬性都有一個描述對象(Descriptor),用來控制該屬性的行爲。Object.getOwnPropertyDescriptor方法能夠獲取該屬性的描述對象。描述對象的enumerable屬性,稱爲」可枚舉性「,若是該屬性爲false,就表示某些操做會忽略當前屬性。
「可枚舉」(enumerable)這個概念的最初目的,就是讓某些屬性能夠規避掉for...in操做,否則全部內部屬性和方法都會被遍歷到。好比,對象原型的toString方法,以及數組的length屬性,就經過「可枚舉性」,從而避免被for...in遍歷到。
Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable // false
從兼容性的角度,都不要使__proto__
用這個屬性,而是使用下面的 Object.setPrototypeOf() (寫操做)、 Object.getPrototypeOf() (讀操
做)、 Object.create() (生成操做)代替。
-------------------------------
Object.entries 的基本用途是遍歷對象的屬性,
Object.entries 方法的一個用處是,將對象轉爲真正的 Map 結構。var map = new Map(Object.entries(obj));
擴展運算符( ... )用於取出參數對象的全部可遍歷屬性,拷貝到當前對象之中。等同於使用 Object.assign 方法。
let aClone = { ...a }; // 等同於 let aClone = Object.assign({}, a);
ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是JavaScript語言的第七種數據類型,前六種是:Undefined、
Null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。
Symbol值經過 Symbol
函數生成。這就是說,對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增
的Symbol類型。凡是屬性名屬於Symbol類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突。
在對象的內部,使用Symbol值定義屬性時,Symbol值必須放在方括號之中。
let s = Symbol(); typeof s // "symbol"
Symbol值能夠顯式轉爲字符串。也能夠轉爲布爾值,可是不能轉爲數值。
Symbol做爲屬性名,該屬性不會出如今 for...in 、 for...of 循環中,也不會
被 Object.keys() 、 Object.getOwnPropertyNames() 返回,它也不是私有屬性,有一
個 Object.getOwnPropertySymbols 方法,能夠獲取指定對象的全部Symbol屬性名。這就形成了一種非私有的內部方法的效果。
Symbol.for() 與 Symbol() 這兩種寫法,都會生成新的Symbol。它們的區別是,前者會被登記在全局環境中供搜索,後者
不會。 Symbol.for() 不會每次調用就返回一個新的Symbol類型的值,而是會先檢查給定的key是否已經存在,若是不存在才
會新建一個值。
-------------------------------
Proxy能夠譯爲「代理器」,ES6原生提供Proxy構造函數,用來生成Proxy實例。
var proxy = new Proxy(target, handler);
Proxy對象的全部用法,都是上面這種形式,不一樣的只是 handler 參數的寫法。其中, new Proxy() 表示生成一個Proxy實
例,target參數表示所要攔截的目標對象, handler 參數也是一個對象,用來定製攔截行爲。
Proxy.revocable方法返回一個可取消的Proxy實例
-------------------------------
Reflect 對象與 Proxy 對象同樣,也是ES6爲了操做對象而提供的新API。
將 Object 對象的一些明顯屬於語言內部的方法(好比 Object.defineProperty ),放到 Reflect 對象上。
-------------------------------
ES6提供了新的數據結構Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。經過 add 方法向Set結構加入成員,結果代表Set結構不會添加劇復的值,一種去除數組重複成員的方法
// 去除數組的重複成員 [...new Set(array)] 或 Array.from(new Set(array));
操做:add(value),delete(value),has(value),clear()
遍歷:keys(),values(),entries(),forEach()
WeakSet結構與Set相似,也是不重複的值的集合。可是,它與Set有兩個區別。
首先,WeakSet的成員只能是對象,而不能是其餘類型的值。
其次,WeakSet中的對象都是弱引用,即垃圾回收機制不考慮WeakSet對該對象的引用,也就是說,若是其餘對象都再也不引用該
對象,那麼垃圾回收機制會自動回收該對象所佔用的內存,不考慮該對象還存在於WeakSet之中。這個特色意味着,沒法引用
WeakSet的成員,所以WeakSet是不可遍歷的。
-------------------------------
ES6提供了Map數據結構,Object結構提供了「字符串—值」的對應,Map結構提供了「值—值」的對應,是一種更
完善的Hash結構實現,Map的鍵其實是跟內存地址綁定的,只要內存地址不同,就視爲兩個鍵
Map原生提供三個遍歷器生成函數keys(),values(),entries(),forEach()
與其餘數據結構的互相轉換
與其餘遍歷語法的比較:
for循環:寫法比較麻煩;
數組提供內置forEach:沒法中途跳出
forEach 循環,break命令或return命令都不能奏效;
for...in循環有幾個缺點:
數組的鍵名是數字,可是for...in循環是以字符串做爲鍵名「0」、「1」、「2」等等。
for...in循環不只遍歷數字鍵名,還會遍歷手動添加的其餘鍵,甚至包括原型鏈上的鍵。
某些狀況下,for...in循環會以任意順序遍歷鍵名。
總之, for...in 循環主要是爲遍歷對象而設計的,不適用於遍歷數組
----
for...of
循環相比上面幾種作法:
有着同for...in同樣的簡潔語法,可是沒有for...in那些缺點。
不一樣用於forEach方法,它能夠與break、continue和return配合使用。
提供了遍歷全部數據結構的統一操做接口。
--------------------------------------------------------------
Promise 是異步編程的一種解決方案,原生提供了Promise對象,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗),一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果,Promise也有一些缺點。首先,沒法取消Promise,一旦新建它就會當即執行,沒法中途取消。其次,若是不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)。
resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從 pending 變爲 resolved)
reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從 pending 變爲 rejected)
then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法
Promise 對象的錯誤具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch語句捕獲。通常來講,不要在then方法裏面定義 Reject 狀態的回調函數(即then的第二個參數),老是使用catch方法。
const p = Promise.all([p1, p2, p3]);
Promise.all方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例。
p的狀態由p一、p二、p3決定,分紅兩種狀況。
(1)只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
Promise.race方法一樣是將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p一、p二、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。
將現有對象轉爲 Promise 對象,Promise.resolve方法就起到這個做用
Promise.resolve('foo')
// 等價於
new Promise(resolve => resolve('foo'))
--------------------------------------------------------------
async 函數是什麼?一句話,它就是 Generator 函數的語法糖。async函數就是將 Generator 函數的星號(*)替換成async,將yield替換成await,僅此而已。
async函數對 Generator 函數的改進,體如今如下四點:
(1)內置執行器。(2)更好的語義。(3)更廣的適用性。(4)返回值是 Promise。
只有async函數內部的異步操做執行完,纔會執行外面的then方法指定的回調函數
// 函數聲明 async function foo() {} // 函數表達式 const foo = async function () {}; // 箭頭函數 const foo = async () => {};
若是但願多個請求併發執行,可使用Promise.all方法。
async 函數的實現原理,就是將 Generator 函數和自動執行器,包裝在一個函數裏。
for...of循環用於遍歷同步的 Iterator 接口。新引入的for await...of循環,則是用於遍歷異步的 Iterator 接口。
異步 Generator 函數出現之後,JavaScript 就有了四種函數形式:普通函數、async 函數、Generator 函數和異步 Generator 函數
--------------------------------------------------------------
Generator函數是ES6提供的一種異步編程解決方案,語法行爲與傳統函數徹底不一樣,形式上,Generator函數是一個普通函數,可是有兩個特徵。一是, function 關鍵字與函數名之間有一個星號;二是,函數體
內部使用 yield 語句,定義不一樣的內部狀態.
Generator函數的調用方法與普通函數同樣,也是在函數名後面加上一對圓括號。不一樣的是,調用Generator函數後並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用 next 方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個 yield 語句(或 return 語句)爲止。
Generator函數是分段執行的, yield 語句是暫停執行的標記,而 next 方法能夠恢復執行。
next方法返回值的value屬性,是Generator函數向外輸出數據;next方法還能夠接受參數,這是向Generator函數體內輸入數據,傳入
Generator 函數,做爲上個階段異步任務的返回結果
Generator函數能夠返回一系列的值,由於能夠有任意多個 yield,yield後面的表達式 123 + 456 ,不會當即求值,只會在 next 方法將指針移到這一句時,纔會求值,Generator函數能夠不用 yield 語句,這時就變成了一個單純的暫緩執行函數。
yield 句自己沒有返回值,或者說老是返回 undefined 。 next 方法能夠帶一個參數,該參數就會被看成上一
個 yield 語句的返回值。
for...of 循環能夠自動遍歷Generator函數,且此時再也不須要調用 next 方法。
Generator函數不能用NEW(會報錯),又想在函數裏面用THIS ?
首先,生成一個空對象,使用 bind 方法綁定Generator函數內部的 this 。這樣,構造函數調用以
後,這個空對象就是Generator函數的實例對象了。
async函數並不屬於ES6,而是被列入了ES7,可是traceur、Babel.js、regenerator等轉碼器已經支持這個功能,轉碼後馬上就
能使用。異步編程對JavaScript語言過重要。Javascript語言的執行環境是「單線程」的,若是沒有異步編程,根本無法用,非卡死不可。
ES6誕生之前,異步編程的方法,大概有下面四種。
回調函數
事件監聽
發佈/訂閱
Promise 對象
-------------------------------
類的數據類型就是函數,類自己就指向構造函數。
class Point{ // ... }
typeof Point // "function"
constructor 方法是類的默認方法,經過 new 命令生成對象實例時,自動調用該方法。一個類必須有 constructor 方法,
若是沒有顯式定義,一個空的 constructor 方法會被默認添加。
實例的屬性除非顯式定義在其自己(即定義在 this 對象上),不然都是定義在原型上(即定義
在 class 上)。hasOwnProperty方法判斷是自己屬性仍是原型屬性。
Class不存在變量提高(hoist),這一點與ES5徹底不一樣。 Class之間能夠經過extends關鍵字實現繼承,這比ES5的經過修改原型鏈實現繼承,要清晰和方便不少
子類必須在 constructor 方法中調用 super 方法,不然新建實例時會報錯。這是由於子類沒有本身的 this 對象,而是繼
承父類的 this 對象,而後對其進行加工。若是不調用 super 方法,子類就得不到 this 對象。只有調用 super 以後,纔可使用 this 關鍵字
類的繼承是按照下面的模式實現的:Object.setPrototypeOf(B.prototype, A.prototype);
Object.getPrototypeOf 方法能夠用來從子類上獲取父類。所以,可使用這個方法判斷,一個類是否繼承了另外一個類。
若是在一個方法前,加上 static 關鍵字,就表示該方法不會被實例繼承,而是直接經過類來調用,這就稱爲「靜態方法」。
父類的靜態方法,能夠被子類繼承
在ES6以前,社區制定了一些模塊加載方案,最主要的有CommonJS和AMD兩種。前者用於服務器,後者用於瀏覽器,ES6模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS和AMD模塊,都只能在運行時肯定這些東西。
let { stat, exists, readFile } = require('fs') 這種加載稱爲「運行時加載」
import { stat, exists, readFile } from 'fs' 這種加載稱爲「編譯時加載」
ES6的模塊自動採用嚴格模式
模塊功能主要由兩個命令構成: export 和 import,export 命令用於規定模塊的對外接口, import 命令用於輸入其餘
模塊提供的功能,export 和 import 命令若是處於塊級做用域內,就會報錯。由於處於條件代碼塊之中,就無法作靜態優化了,違背了ES6模塊的設計初衷
模塊的總體加載 import * as circle from './circle';
export default 命令,爲模塊指定默認輸出,一個模塊只能有一個默認輸出,因此, import 命令後面纔不用加大括號,由於只可能對應一個方法
編碼規範:
(1)let取代var
(2)全局常量和線程安全:在 let 和 const 之間,建議優先使用 const ,尤爲是在全局環境,不該該設置變量,只應設置常量。
..靜態字符串一概使用單引號或反引號,不使用雙引號。動態字符串使用反引號。
..使用數組成員對變量賦值時、函數返回多個值,優先使用解構賦值。
..單行定義的對象,最後一個成員不以逗號結尾。多行定義的對象,最後一個成員以逗號結尾。
..對象儘可能靜態化,一旦定義,就不得隨意添加新的屬性。若是添加屬性不可避免,要使用 Object.assign 方法
..使用擴展運算符(...)拷貝數組,使用Array.from方法,將相似數組的對象轉爲數組。
..當即執行函數能夠寫成箭頭函數的形式,那些須要使用函數表達式的場合,儘可能用箭頭函數代替。由於這樣更簡潔,並且綁定了this。
..不要在函數體內使用arguments變量,使用rest運算符(...)代替
..老是用Class,取代須要prototype的操做 ..Module語法是JavaScript模塊的標準寫法,堅持使用這種寫法。使用 import 取代 require 。 -------------------------------