1. 認識 ES6
1. ECMAScript 和 JavaScript 關係
ECMA
是 “European Computer Manufacturers Association"
的縮寫,中文稱歐洲計算機制造聯合會,這個組織的目標是評估,開發和認可電信和計算機標準
ECMA
是標準,JavaScript
是實現
類似 HTML5
是標準,IE10
,Chrome
,FF
都是實現
目的是讓所有前端腳本都實現 ECMA
目前只有 JavaScript
實現 ECMA
標準
ECMAScript
簡稱 ECMA
或 ES
(ES6
)
目前版本
高級瀏覽器支持 ES6
低級瀏覽器主要支持 ES3.1
2. ECMA 標準出臺流程
ECMAScript
是跨多個平臺的許多廠商(包括瀏覽器廠商在內的各方組成)實施的不斷髮展的標準。
ES6(ECMAScript 2015)
花費六年的時間敲定,是一個很大的發行版。新的年度發佈流程被制定,以簡化流程並更快的添加功能。
ES9(ES2018)
是目前的最新版本。推動 JavaScript 提案沿着一條嚴格的發展道路前進:
strawman
----- 最初想法的提交
proposal(提案)
------ 由至少一名成員倡導的正式提案文件,該文件包括 API
事例
draft(草案)
----- 功能規範的初始版本,該版本包含功能規範的兩個實驗實現
candidate(候選)
------ 提案規範通過審查並從廠商那裏收集反饋
finished(完成)
------ 提案准備加入 ECMAScript
,但是到瀏覽器或者 Node.js
中可能需要更長的時間
3. 接觸 ES6 的意義
對語法的改進,功能的增加
使用 Vue,React,小程序,Node.js 等都在用
2. ES6 兼容性解決
var fn = (
v => console. log ( v) ;
)
轉爲
"use strict"
var fn = function fn ( v) {
return console. log ( v) ;
} ;
1. 使用 Babel 工具
使用 npm 來安裝 babel,npm 是隨同 Node.js 一起安裝的包管理工具,新版的 Node.js 已經繼承了 npm ,只要安裝 Node.js 即可
在命令行安裝:
2. 在線轉換
在安裝位置下找到 node_modules\babel-core\lib\api\browser.js
https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js
< script src = " browser.js" > </ script>
< script type = " text/babel" >
const Name = '張三' ;
alert ( Name) ;
</ script>
3. 提前編譯
改鏡像(可不改)
npm config set registry https://registry.npm.taobao.org/
npm config get registry
輸入 npm install babel-cli-g
來全局安裝 babel-cli
找一個目錄,用 npm
來初始化一個項目,用來搭建我們的 babel
環境
進入 babel
目錄,然後打開命令行工具驗證環境
babel-node
是 babel
提供的一個編譯工具,也可執行 js 代碼
在 babel
目錄新建 .babelrc
文件(這是 babel
的配置文件)
( echo . > . babelrc)
{ "presets" : [ "es2015" , "stage-2" ] ,
"plugins" : [ "transform-runtime" ]
}
安裝需要的庫:
npm install babel-core babel-preset-es2015 babel-plugin-transform-runtime babel-preset-stage-2 -save-dev
打開 babel
項目下的 package.json
文件,做如下修改
"scripts" : {
"build" : "babel src -w -d lib"
}
編譯整個 src
目錄(需要轉換的目錄
)並將其輸出到 lib
目錄(輸出內容的存放目錄
),-w
其實是 -watch
的意思,就是監聽文件,實時編譯輸出
新建 src
目錄和 lib
目錄,記得一定要建,不然會報錯,然後啓動 babel
工程
4. Babel 兼容性列表
ES6 特性
兼容性
箭頭函數
支持
類的聲明和繼承
部分支持,IE8不支持
增強的對象字面量
支持
字符串模版
支持
解構
支持,但注意使用方式
參數默認值,不定參數,拓展參數
支持
let 與 const
支持
for of
IE 不支持
iterator,generator
不支持
模版 module,Proxies,Symbol
不支持
Map,Set 和 WeakMap,WeakSet
不支持
Promises,Math,Number,String,Object 的新 API
不支持
export & import
支持
生成器函數
不支持
數組拷貝
支持
3. let 和 const
1. var 命令
var a = 10 ;
var a = 20 ;
console. log ( a) ;
var a = 10 ;
a = 30 ;
if ( true ) {
var a = 10 ;
console. log ( a) ;
}
console. log ( a) ;
2. let 命令
ES6
新增 let
命令,用來聲明變量。用法類似於 var
let
不能重複聲明
let a = 10 ;
let a = 20 ;
console. log ( a) ;
let
聲明的變量,只在 let
命令所在的代碼塊內有效
let
具有塊級作用域
例子一:
if ( true ) {
let a = 10 ;
console. log ( a) ;
}
console. log ( a) ;
例子二:
for ( var i= 0 ; i< 10 ; i++ ) {
console. log ( i) ;
}
console. log ( i) ;
for ( let i= 0 ; i< 10 ; i++ ) {
console. log ( i) ;
}
console. log ( i) ;
< input type = " button" value = " one" >
< input type = " button" value = " two" >
< input type = " button" value = " three" >
< script>
window. onload = function ( ) {
var btns = document. getElementsByTagName ( "input" ) ;
for ( var i= 0 ; i< btns. length; i++ ) {
( function ( i) {
btns[ i] . onclick = function ( ) {
console. log ( i + 1 ) ;
}
} ) ( i) ;
}
for ( let i= 0 ; i< btns. length; i++ ) {
btns[ i] . onclick = function ( ) {
console. log ( i + 1 ) ;
}
}
}
</ script>
3. const 命令
const
命令聲明一個只讀的常量
一旦聲明,常量的值就不能改變
const PI = 3.1415 ;
console. log ( 'PI=' + PI ) ;
PI = 3 ;
const
命令聲明的常量不得改變值,即一旦聲明,就必須立即初始化
const a = 10 ;
const foo;
const
命令聲明的常量,只在聲明所在的塊級作用域內有效
const
命令聲明的常量不提升,只能在聲明的位置後使用
const
命令聲明的常量,與 let
一樣不可重複聲明
4. const 命令本質
const
實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址不得改動
對於簡單類型的數據(數值,字符串,布爾值
),值就保存在變量指向的那個內存地址,因此等同於常量
但對於複合類型的數據(主要是對象
和數組
),變量指向的內存地址
,保存的只是一個指針
,const
只能保證這個指針
是固定的,至於它指向的數據結構是不是可變的,就完全不能控制了
因此,將一個對象聲明爲常量必須非常小心
const foo = { } ;
foo. prop = 123 ;
console. log ( foo. prop) ;
foo = { } ;
分析:
上面的代碼中,常量 foo 存儲的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把 foo 指向另一個地址,但對象本身是可變的,所以依然可以爲其添加新屬性。
4. 箭頭函數
1. 基本用法
var f = v => v;
var f = function ( v) {
return v;
}
var f = ( ) => 5 ;
var f = function ( ) {
return 5
} ;
var sum = ( num1, num2) => num1+ num2;
var sum = function ( num1, num2) {
return num1 + num2;
}
代碼塊部分多於一條語句,就用大括號括起來,並且用 return
返回
var sum = ( num1, num2) => { return num1+ num2; }
var getTempItem = id => ( { id: id, name: 'Temp' } ) ;
console. log ( getTempItem ( 2 ) ) ;
const isEven = n => n % 2 == 0 ;
const square = n => n * n;
[ 1 , 2 , 3 ] . map ( function ( x) {
return x * x;
) }
[ 1 , 2 , 3 ] . map ( x => x * x) ;
var result = values. sort ( function ( a, b) {
return a - b;
} ) ;
var result = values. sort ( ( a, b) => a - b) ;
2. this 指向問題
2.1 普通函數中的 this
:
this
總是代表它的直接調用者(js
的 this
是執行上下文)
例如 obj.func
,那麼 func
中的 this
就是 obj
在默認情況下(非嚴格模式下,未使用 ‘use strict
’),沒找到直接調用者,則 this
指的是 window
(約定俗成)
在嚴格模式下,沒有直接調用者的函數中的 this
是 undefined
使用 call
,apply
,bind
(ES5
新增)綁定的,this
指的是綁定的對象
2.2 箭頭函數中的 this
:
箭頭函數沒有自己的 this,它的 this 是繼承而來的;默認指向在定義它時所處的對象(宿主對象)
,而不是執行時的對象,定義它的時候,可能環境是 window
;箭頭函數可以方便地讓我們在 setTimeout
,setInterval
中方便的使用 this
箭頭函數中,this
指向的固定化,並不是因爲箭頭函數內部有綁定 this
的機制,實際原因是箭頭函數根本沒有自己的 this ,導致內部的 this 就是外層代碼塊的 this
function Person ( ) {
this . name = 'little bear123' ,
this . age = 1234
setInterval ( ( ) => {
console. log ( this ) ;
console. log ( '我叫' + this . name + '我今年' + this . age + '歲' )
} , 10000 )
}
let p = new Person ( )
Person{ name: "little bear123" , age: 1234 }
我叫little bear123我今年1234 歲
這段函數中,this 指向的是 `Person` 對象,可以看到控制檯打印結果,此時的箭頭函數所處的宿主對象是 `Person` ,所以 this 指向的是 `person`
5. 數組的新增方法
1. map 映射
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
let narr = arr. map ( function ( item) {
console. log ( item) ;
return item* item;
) ) ;
let narr = arr. map ( item => item* item) ;
console. log ( narr) ;
2. reduce 彙總
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
let narr = arr. reduce ( ( a, b, c) => {
console. log ( a, b, c) ;
return a+ b;
} ) ;
let narr = arr. reduce ( ( a, b, c) => a+ b) ;
console. log ( narr) ;
3. filter 過濾器
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
let narr = arr. filter ( item => item% 3 == 0 ) ;
console. log ( narr) ;
4. forEach 循環(迭代)
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
arr. forEach ( ( value, index) => {
console. log ( index, value) ;
} ) ;
5. some()
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
let narr = arr. some ( item => item> 10 ) ;
console. log ( narr) ;
6. every()
let arr = [ 2 , 4 , 6 , 8 , 10 ] ;
let narr = arr. every ( item => item> 2 ) ;
console. log ( narr) ;
6. 字符串和模版字符串
1. 字符串新方法
startsWith
判斷以什麼字符串開頭
endsWith
判斷以什麼字符串結尾
let url = "https://www.baidu.com/" ;
if ( url. startsWith ( "http://" ) ) {
console. log ( '普通URL' ) ;
} else if ( url. startsWith ( "https://" ) ) {
console. log ( '加密URL' ) ;
} else if ( url. startsWith ( 'ftp://' ) ) {
console. log ( '文件傳輸協議' ) ;
}
let str = "logo.jpg" ;
if ( str. endsWith ( ".jpg" ) ) {
console. log ( '圖片' ) ;
} else if ( str. endsWith ( ".txt" ) ) {
console. log ( '文本' ) ;
}
2. 模版字符串
$ ( '#result' ) . append (
'There are <br>' + basket. count + '</b>' +
'items in your basket,' +
'<em>' + basket. onSale +
'</em> are on sale'
) ;
$ ( '#result' ) . append ( `
There are <b> ${ basket. count} </b> items
in your basket,<em> ${ basket. onSale} </em>
are on sale!
`
) ;
模版字符串(template string
)是增強版的字符串,用反引號標識
。他可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。
`In JavaScript '\n' is a line-feed.`
`In JavaScript this is
not legal.`
console. log ( `string text line 1
string text line2` ) ;
var name = "Bob" , time = "today" ;
console. log ( `Hello ${ name} , how are you ${ time} ?` ) ;
7. 函數的參數
1. 參數擴展
let arr = [ 1 , 2 , 3 , 4 ] ;
let arr2 = [ 5 , 6 , 7 , 8 ] ;
let narr = [ ... arr, ... arr2] ;
let xarr = ... arr;
console. log ( narr) ;
2. 展開數組
function demo ( ... args) {
console. log ( args) ;
}
demo ( 1 , 2 , 3 , 4 , 5 , 6 , ... ) ;
3. 默認參數
functon demo ( a, b= 2 , c= 3 , d) {
console. log ( a, b, c, d) ;
}
demo ( 1 , 5 , 8 ) ;
8. 解構賦值
let [ a, b, c] = [ 1 , 2 , 3 ] ;
let { a, b, c} = { a: 12 , b: 2 , c: 4 } ;
let [ { a, b} , [ c, d, e] , num, str] = [ { a: 12 , b: 33 } , [ 12 , 4 , 3 ] , 8 , 'saf' ] ;
let [ json, arr, num, str] = [ { a: 12 , b: 33 } , [ 12 , 4 , 3 ] , 8 , 'saf' ] ;
let { a, b} = { 12 , 5 } ;
let { a, b} = { a, b} ;
let [ a, b] ;
[ a, b] = [ 12 , 5 ] ;
9. Class 用法
1. Class 基本用法
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 ) ;
class Point {
constructor ( x, y) {
this . x = x;
this . y = y;
}
toString ( ) {
return '(' + this . x + ',' + this . y + ')' ;
}
}
2. Class 類的繼承
class Person {
constructor ( name, age) {
this . name = name;
this . age = age;
}
say ( ) {
console. log ( this . name + "===" + this . age) ;
}
}
class Teacher extends Person {
constructor ( name, age, school) {
super ( name, age) ;
this . school = school;
}
study ( ) {
console. log ( this . name+ "===" + this . age+ "===" + this . school) ;
}
}
let t = new Teacher ( "張三" , 12 , 'html' ) ;
t. say ( ) ;
t. study ( ) ;
10. JSON 新應用
1. json的標準寫法
只能用雙引號(""
)
所有的(屬性
)名字只能用雙引號(""
)包起來
let str = { "a" : 1 , "b" : "abc" , "c" : true }
2. JSON 對象
let obj = { a: 10 , b: 20 , c: 30 } ;
let str = JSON . stringify ( obj) ;
console. log ( str) ;
let str = { "a" : 10 , "b" : 20 , "c" : 30 } ;
let obj = JSON . parse ( str) ;
console. log ( obj) ;
3. 簡寫
(屬性和值
)名字一樣可以簡寫
方法一樣可以簡寫(:function省
)
11. Promise 應用
Promise
,簡單說就是一個容器,裏面保存着某個未來纔會結束的事件(通常是一個異步操作--接口--Ajax--setTimeout--img
)的結果
ES6
規定,Promise
對象是一個構造函數,用來生成Promise
實例
const promise = new Promise ( ( resolve, reject) => {
if ( ) {
resolve ( value) ;
} else {
reject ( error) ;
}
} ) ;
Promise
構造函數接受一個函數作爲參數,該函數的兩個參數分別是resolve
和reject
,它們是兩個函數,由JavaScript引擎
提供,不用自己部署
resolve
函數的作用是,將Promise
對象的狀態從“未完成”變爲“成功”,在異步操作成功時調用,並將異步操作的結果,作爲參數傳遞出去
reject
函數的作用是,將Promise
對象的狀態從“未完成”變爲“失敗”(即從pending變爲rejected
),在異步操作失敗時調用,並將異步操作報出的錯誤,作爲參數傳遞出去
Promise
實例生成後,可以用 then
方法分別指定 resolved
狀態和 rejected
狀態的回調函數
promise. then ( function ( value) {
} , function ( error) {
} ) ;
then
方法可以接受兩個回調函數作爲參數。
第一個回調函數是 Promise
對象的狀態變爲 resolved
時調用
第二個回調函數是 Promise
對象的狀態變爲 rejected
時調用。
其中,第二個函數是可選的,不一定要提供。這兩個函數都接受 Promise
對象傳出的值作爲參數
1. Promise 的使用
let one = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'aa' ) :
} , 1000 ) ;
} )
let two = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'bb' ) :
} , 1000 ) ;
} )
let three = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'cc' ) :
} , 1000 ) ;
} )
Promise. all ( [ one, two, three] ) . then ( arr=> {
let [ one, two, three] = arr;
console. log ( one) ;
console. log ( two) ;
console. log ( three) ;
let one = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'aa' ) :
} , 1100 ) ;
} )
let two = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'bb' ) :
} , 1050 ) ;
} )
let three = new function ( ) {
setTimeout ( ( ) => {
resolve ( 'cc' ) :
} , 1300 ) ;
} )
Promise. race ( [ one, two, three] ) . then ( arr=> {
console. log ( arr) ;
}
function foo ( ) {
return new Promise ( ( resolve, reject) => {
setTimeout ( ( ) => {
resolve ( ) ;
} , 1000 )
} ) ;
}
foo ( ) . then ( ( ) => {
console. log ( 'aa' ) ;
return foo ( ) ;
} ) . then ( ( ) => {
console. log ( 'bb' ) ;
console, log ( data) ;
return foo ( ) ;
} ) . catch ( rea=> {
console. log ( 'error' ) ;
console. log ( rea) ;
} ) ;
async function demo ( ) {
console. log ( 'this is a async demo' ) ;
}
console. log ( demo ( ) ) ;
function demo ( ) {
return new Promise ( ( resolve, reject) => {
setTimeout ( ( ) => {
resolve ( 2 * num) ;
} , 2000 )
} )
}
async function test ( ) {
await demo ( 20 ) ;
}
test ( ) ;
12. generator 應用
1. generator 和 yield 的使用
Generator
主要用於異步編程,就是封裝一個異步任務,或者說是異步任務的容器
特點是可以交出函數執行全(展停執行)
在聲明函數的 function
關鍵字與函數名之間有一*(用於區別普通函數)
yield
在 Generator
函數體內使用,可以定義不同的內部狀態(可以設置不同時候不一樣的值)
yield
命令是異步不同階段的分界線,有時也會把 yield
當成是 return
(當然有本質區別)
使用啓動 next()
方法,分階段執行 Generator
函數
function * demo ( ) {
console. log ( '1' ) ;
yield
console. log ( '2' ) ;
yield
console. log ( '3' ) ;
}
let genob = demo ( ) ;
genobj. next ( ) ;
genobj. next ( ) ;
genobj. next ( ) ;
13. Map 數據結構
Map 數據結構類似於對象,是鍵值對的集合,傳統的鍵只能用字符串,Map的鍵不限於字符串,各種類型的值(包括對象)都可以當作鍵
1. 屬性和操作方法
const map = new Map ( ) ;
map. set ( 'foo' , true ) ;
map. set ( 'bar' , false ) ;
map. size
set(key, value)
set
方法設置 set
方法設置鍵名 key
對應的鍵值爲 value
,然後返回整個 Map
結構,如果 key
已經有值,則鍵值會被更新,否則就新生成該鍵
const m = new Map ( ) ;
m. set ( 'edition' , 6 )
m. set ( 262 , 'standard' )
m. set ( undefined, 'nah' )
14. Module 模塊
export 命令
export var firstName = 'Michael' ;
export var lastName = 'Jackson' ;
export var year = 1958 ;
var firstName = 'Michael' ;
var lastName = 'Jackson' ;
var year = 1958 ;
export { firstName, lastName, year} ;
一個模塊就是一個獨立的文件,該文件內部的所有變量,外部無法獲取,如果你希望外部能夠讀取模塊內部的某個變量,就必須使用 export
關鍵字輸出該變量
export function multiply ( x, y) {
return x * y;
} ;
function v1 ( ) { ... }
function v2 ( ) { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatesVersion
} ;
15. ES7-ES9 新特性
1. ES7 新功能
Array.prototype.includes
檢查數組中是否存在值;(區別ES6
字符串的includes
方法)
Exponentiation Operator
求冪運算(a**b等價於Math.pow(a,b)
)
2. ES8 部分功能
Object.values/entries/getOwnProertyDescriptors
String.prototype.padStart/padEnd
函數參數列表和調用中的尾逗號(trailing commas
)
Async Functions
異步函數(async/await
)
3. ES9 新增部分功能
異步迭代
Promise.finally()
Rest/Spread
屬性
正則表達式命名捕獲組
正則表達式反向斷言
非轉義序列的模版字符串