介紹
ES6:ECMScript6
首先,一個常見的問題是,ECMAScript 和 JavaScript 到底是什麼關係?
-
ECMAScript是一個國際通過的標準化腳本語言;
-
JavaScript由ECMAScript和DOM、BOM三者組成;
-
可以簡單理解爲:ECMAScript是JavaScript的語言規範,JavaScript是ECMAScript的實現和擴展;
2011 年,ECMAScript 5.1 版發佈。之前我們大部分人用的也就是ES5。
2015 年 6 月,ECMAScript 6 正式通過,成爲國際標準。
塊級作用域
- ES5 中作用域有:全局作用域、函數作用域(function scope)。沒有塊作用域(block scope)的概念。
- ES6 中新增了塊級作用域。塊作用域由 { } 包括,if語句和 for語句裏面的{ }也屬於塊作用域。
變量聲明
變量聲明的三種方式:var
、let
、const
var
聲明的變量屬於函數作用域(function scope),函數內部有效,可以在同一個作用域重複聲明和賦值;
let
聲明的變量屬於塊級作用域(block scope),塊作用域內部有效;
const
聲明的變量定義爲常量,使用時必須初始化(賦值),屬於塊級作用域,塊級作用域內部有效;
比較 | var | let | const |
---|---|---|---|
所屬作用域 | 函數作用域 | 塊級作用域 | 塊級級作用域 |
是否可以重複聲明 | 可以 | 作用域內不可以 | 作用域內不可以 |
是否可以重複賦值 | 可以 | 可以 | 不可以 |
未賦值時打印 | undefined | undefined | 必須賦值 |
臨時性死區和變量提升
臨時性死區:Temporal Dead Zone(TDZ);
變量提升:Hoisting;
console.log(color); //undefined 變量提升
var color = 'yellow';
在JavaScript中,function中variables(變量)會被提升;
變量提升是指JavaScript將聲明移至當前作用域(scope)頂部的行爲;
所以以上代碼可以理解爲:
var color;
console.log(color); //undefined
color = 'yellow';
對於let和const關鍵字來說也有變量提升的概念,但是在let和const中還存在一個臨時性死區的概念,即在當前變量的作用域開始到變量聲明之前都是處在臨時性死區中的,處於臨時性死區的變量引用時會報referenceError錯誤;
{
console.log(color); //referenceError 臨時性死區
let color = 'yellow';
}
var、let、const取捨之道
- 默認使用
const
聲明變量(useconst
by default) - 當需要改變變量值時使用
let
(only uselet
if rebinding is needed) - 儘量不使用
var
(var
shouldn’t be used in ES6)
箭頭函數
arrow function
示例:
const numbers = [5,6,13,0,1,18,23];
//一般方式
const double = numbers.map(function(number){
return number * 2;
})
//箭頭函數,當且僅當只有一個參數時可以省略小括號,無參數也不可省略
const double2 = numbers.map(number => {
return number * 2;
})
//箭頭函數,當函數內部只有一句時可以省略大括號,稱爲隱式返回
const double2 = numbers.map((number, i)=> number * 2);
箭頭函數屬於匿名函數,可以通過賦值給變量得到匿名函數引用;
const greet = number => {alert('The number is ${number}')};
箭頭函數沒有其this值,它的this值是繼承於它的父作用域的;
const Jelly = {
name: 'jelly',
hobbies: ['coding', 'Sleeping', 'Reading'],
printHobbies: function(){
this.hobbies.map(function(){
console.log(this) // Window,全局變量,嚴格模式下undefined
})
//修改爲箭頭函數即可
this.hobbies.map(() => {
console.log(this) // Jelly
})
}
}
模板字符串
ES6提供了模板字符串,使用模板字符串可以更簡潔的進行字符串的拼接,也可以直接在模板字符串中書寫html代碼,由此可以方便的引用模板;
const user = 'tom';
const pass = '123';
const sentence = 'username: '+ user + ', password: '+ pass;
console.log(sentence);
const sentence2 = `username: ${user} , password: ${pass}`; //使用模板字符串
console.log(sentence2);
對象解構
const user = {
name : 'tom',
pass : '123'
}
const {name : n, pass, age = 18 } = user
console.log(n) // 'tom'
console.log(name) // undefined
console.log(age) //18
我們在結構對象變量後面可以設置變量的別名,此時初始化的爲別名變量,原名變量爲聲明即爲undefined;
如果我們在解構聲明變量時,定義了對象中不存在的屬性,那麼這個變量的值爲undefined
。我們可以給變量設置默認值,當對象中沒有對應的屬性時,這個變量的值就是設置的默認值。
數組解構
const numbers = ['one', 'two', 'three', 'four'];
const [one, two] = numbers; // 獲得第一個和第二個位置的值
const [one, ,three] = numbers; // 獲得第一、三位置的值
const [one, ...others] = numbers; // 獲得第一和後面所有的值
console.log(one, others) // one ['two', 'three', 'four']
數組解構和對象解構類似,也可以在變量聲明的後面起別名,賦初值等。。。
for of循環
const numbers = ['one', 'two', 'three', 'four'];
//普通for循環
for(let i = 0; i< numbers.length; i++){
console.log(numbers[i]);
}
//forEach遍歷
numbers.forEach(number => {
console.log(number);
})
//for in循環
for(let index in numbers){ //每次循環的是索引值,且遍歷過程中不可中斷(break)
console.log(numbers[index]);
}
//for of循環
for(let number of numbers){ //每次循環的是屬性值;可使用break和continue
console.log(number)
}
for of 循環可以利用entries()同時獲得索引值和屬性值;
for(let [index, number] of numbers.entries()){
console(index,number)
}
對象轉數組
當你需要使用數組的方法迭代一個可迭代對象時,而該對象又不是數組類型,你可以使用Arrat.from()方法把對象轉化爲數組類型的對象;
Arrat.from(object)可以把其他對象轉化爲數組;
Array.of()創建數組
Array.of()彌補了Array構造函數的不足,不管傳入多少參數返回的都是這些參數組成的數組;
new Array(4) // (3) [empty × 3]
new Array(4,1) // [4, 1]
Array.of(4) //[4]
Array.of(4,1) //[4, 1]
數組新方法
方法 | 說明 |
---|---|
find((element, index, array)=>{}) | 該方法接收的參數是一個函數,其中有三個可選參數,element表示要遍歷的元素,index表示索引,array表示調用方法的數組,當找到數組中的元素或索引後立即返回該元素或索引; |
findIndex() | 該方法與find方法類似,返回的是尋找元素的索引值; |
some() | 參數是一個函數,返回布爾值,true的條件是數組中含有至少一個條件滿足 |
every() | 參數、返回值同some,true的條件是數組中所有條件都滿足 |
const fruits = [
{name: 'apple', quantity: 2},
{name: 'banana', quantity: 0},
{name: 'orange', quantity: 5}
];
// find()
const banana = fruits.find(fruit => {
if(fruit.name === 'banana'){
return true;
}
return false;
});
// findIndex()
const bananaIndex = fruits.findIndex(fruit => fruit.name === 'banana');
//some()
const isEnough = fruits.some(fruit => fruit.quantity > 0); //true
//every()
const isAllEnough = fruits.every(fruit => fruit.quantity > 0); //false
剩餘參數
ES6中可以使用...params
接收參數列表中的從聲明位置到最後的所有參數,param返回爲一個數組
function sum(...numbers){
return numbers.reduce((prev,curr) => prev + curr, 0)
} //reduce()方法接收一個函數callbackfn作爲累加器(accumulator),數組中的每一個值(開始合併),最後成爲一個值。
console.log(sum(1,2,3,4)) //10
console.log(sum(1,2,3)) //6
擴展運算符
擴展運算符和剩餘參數作用相反,剩餘參數是把參數序列整合成一個數組;
而擴展運算符是把一個可遍歷對象的每一個元素擴展爲一個新的參數序列;
const youngers = ['George', 'John', 'Thomas'];
const olders = ['James', 'Adrew', 'Martin'];
//const members = [];
//members.concat(youngers);
//members.concat(olders);
const members = [...youngers, 'mary', ...olders];
//數組之間的賦值
const currentMembers = [...members];
// const currentMembers = members 此時傳遞的是引用,修改其中一個值,另一個數組也會隨之改變;
// const currentMembers = [].concat(members) //可以替換爲這種方式
對象字面量的擴展
在ES6中,當對象屬性名和參入參數名相同時,不需要再重複兩次;
const name = 'Tom';
const age = 12;
const sex = 'male';
const Tom = {
//name : name,
name,
age,
sex,
func(){} //對象方法的簡寫
//func:function(){} //簡寫前
}
promise解決回調地獄
需求:確保第二個函數是在第一個函數執行之後執行(函數可能是發起的ajax請求);
回調地獄是指在上述需求中當需要嵌套很多函數時,不得不把下一個函數寫在上一個函數的回調函數中,這樣層層嵌套就會導致回調地獄;
ES6中提供了promise來解決回調地獄的問題,提高代碼的可讀性;
回調地獄:
$.get('http://api.github.com/users', data =>{
user = data[0].login;
//第二個請求要使用第一個的內容,所以要在第一個函數執行完再執行
$.get(`http://api.github.com/users/${user}/repos`, data =>{
//業務邏輯
//或許還需要第三個請求在第二個請求執行後執行
//這裏就形成了回調地獄
})
})
promise:
axios 提供了promise功能
//返回promise
const usersPromise = axios.get('https://api.github.com/users');
userPromise
.then(response => { //response是請求成功後返回的響應對象
user = response.data[0].login;
//返回的promise
return axios.get(`http://api.github.com/users/${user}/repos`);
})
.then(response =>{ //可以直接在後面鏈接調用
//業務邏輯
//其他請求
})
.catch(err =>{ //可以使用catch獲取錯誤信息
console.error(err);
})
自定義promise
可以自定義promise來完成需要的異步操作,在js中所有代碼都是單線程執行的。
可以通過Promise的構造方法來自定義一個Promise,構造方法中是一個回調函數,函數有兩個參數;
- resolve保存的是成功之後返回的信息;
- reject保存的是失敗的信息;
const p = new Promise((resolve, reject) => {
resolve('這裏是成功之後返回的信息');
reject(Error('這裏是調用失敗返回的信息'));
});
p.then(data => {console.log(data) }) //這裏是成功之後返回的信息
.catch(err => {console.log(err) }) //這裏是調用失敗返回的信息
基本數據類型
ES6中引入了一種新的基本數據類型:Symbol
之前還有五種基本數據類型:undefined
,boolean
,string
,number
,object
,null
Symbol用來解決屬性名衝突的問題;
const tom = Symbol('tom'); //定義方法
const people = {
[Symbol('mary')] : {age: 12, sex:'famale' },
[Symbol('mary')] : {age: 15, sex:'famale' }, //不會覆蓋上面的mary
[Symbol('jack')] : {age: 13, sex:'male' }
}
注意:Symbol類型的值不能夠被獲取遍歷,除非使用ES6提供的Object.getOwnPropertySymbols(people);
ES6模塊
import moduleName from 'module'
定義模塊
name.js
const myname = 'tom';
export default myname; //默認導出,只能有一個默認導出
export const myname = 'tom'; //命名導出,其他文件引入時命名需要保持一致性,且需要使用大括號包裹,可以有多個
export function getname(name){ //函數導出同命名導出
console.log(name);
}
引用模塊
app.js
import myname from './name'; //默認導出引用方式
import {myname,getname} from './name'; //命名導出+函數導出引用方式
console.log(myname) //tom
注意:相同的導出和引用使用一個即可,上面代碼是爲了簡化書寫;