本文主要記錄常見的es6基礎知識
目錄
- es6是什麼
- let和const
- 字串模板
- 解構賦值
- set和map
- 箭頭函式
- class類和extends
- promise
- async/await
- export和import
1. es6是什麼
ECMAScript 6(以下簡稱ES6)是JavaScript語言的下一代標準。因為當前版本的ES6是在2015年釋出的,所以又稱ECMAScript 2015(簡稱ES2015)。雖然瀏覽器在不斷更新,但並不是所有使用者的電腦瀏覽器都支援ES6,所以在使用的過程中建議還是轉成es5,保證程式碼的可執行性。至於轉換的方式大家可以用Babel或者Traceur轉碼器。
ECMAScript的幾次大版本:es3-->es5-->es6(es7相對於es6變動不大)
2. let 和 const
let
在es5裡,定義變數用var,即相當於在全域性宣告一個變數,由於js沒有塊級作用域,會導致在使用變數的過程中存在變數提升的概念。
console.log(a); // undefined
var a = 10;
console.log(a) //10
function fn () {
console.log(a); // undefined
var a = 'aaa';
console.log(a); // aaa
}
fn();
複製程式碼
在C,Java等語言中,變數必須先申明在使用,否則會報錯,但是在js中由於變數提升的原因不會報錯。
關於var定義變數還有一個經典的實列:
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i)
},1000)
}
//5 5 5 5 5
複製程式碼
結果並不是預期的 0,1,2,3,4。這是因為由於js內部的執行機制,遇到定時器任務以及非同步請求時其回撥函式會先放到任務隊中,優先執行主程式任務,待主程式執行完畢再執行任務佇列中的程式碼。es5中用閉包來解決這個問題,使用了立即執行函式:
for(var i=0;i<5;i++){
(function(i){
setTimeout(function(){
console.log(i)
},1000)
})(i)
}
// 0 1 2 3 4
複製程式碼
當然,也可以使用es6中的let,簡潔方便,直接將var改為let即可。
下面的列題方面理解,點選標籤彈出對應索引:
window.onload = function(){
var aInput = document.getElementsByTagName("input");
// 傳統解決辦法
for(var i=0;i<aInput.length;i++){
(function(i){
// 函式閉包自執行來解決i索引的問題
aInput[i].onclick = function(){
alert(i);
};
})(i);
}
// let變數的出現相當於給你加了一個封閉空間來極度簡化了i值索引的問題
// let大家可以看成是匿名函式立即呼叫(IIFE)
for(let i=0;i<aInput.length;i++){
aInput[i].onclick = function(){
alert(i);
};
}
};
複製程式碼
const
es6中使用const來定義常量,顧名思義即不變的量,不可修改(這裡指的是普通常量,比如字串,數字,boolean),當對一個物件常量修改其屬性則是允許的。
const a = 10;
a = 20
//報錯: Uncaught SyntaxError: Identifier 'a' has already been declared
const obj = {
a: 1,
name: 'hello'
}
obj.a = 2
obj.name = 'world'
console.log(obj)
//{a: 2,name: 'world'}
複製程式碼
關於let和const的使用會存在 暫死性區域
3. 字串模板
在es5中使用字串拼接常這樣來做:
let name = 'wjb'
console.log('i am ' + name)
複製程式碼
當遇到字串比較長,涉及到的變數比較多的時候就顯得不那麼好看和使用了,es6新增字串拼接方法,使用``包裹內容,${}描述變數:
let name = 'wjb'
console.log(`i am ${name}`)
複製程式碼
4.解構賦值
// 以前我們給變數賦值,只能直接指定值
var a = 1;
var b = 2;
var c = 3;
console.log(a,b,c); // 1 2 3
// 現在用解構賦值的寫法就變得簡單了,只要模式匹配上了就行了,如下
// 注意陣列是有順序的
var [a,b,c] = [11,22,33];
console.log(a,b,c); // 11 22 33
var [b,a,c] = [11,22,33];
console.log(a,b,c); // 22 11 33
// 當然解構賦值還有巢狀比較複雜的寫法,如下
let [foo,[[bar],[baz]]] = [111,[[222],[333]]];
console.log(foo,bar,baz); // 111 222 333
let [head,...foot] = [1,2,3,4];
console.log(head,foot); // 1 [2,3,4]
// 如果解構不成功,變數的值就等於undefined,如下
var [bar3,foo3] = [1000];
console.log(bar3,foo3); // 1000 undefined
// 另一種情況是不完全解構,即等號左邊的模式,只匹配一部分的等號右邊的陣列。這種情況下,解構依然可以成功
let [x,y] = [10000,20000,30000];
console.log(x,y); // 10000 20000
// 預設值可以引用解構賦值的其他變數,但該變數必須已經宣告
let [a=1,b=a] = [2,3];
console.log(a,b); // 2 3
// 物件的解構也可以指定預設值
var {x,y=5} = {x:1};
console.log(x,y); // 1 5
//物件的解構賦值解構不僅可以用於陣列,還可以用於物件(json)
//物件的解構與陣列有一個重要的不同。陣列的元素是按次序排列的,變數的取值由它的位置決定;
//而物件的屬性沒有次序,變數必須與屬性同名,才能取到正確的值
var {a,b} = {a:'apple',b:'banana'};
console.log(a,b); // apple banana
var {b,a} = {a:'apple',b:'banana'};
console.log(a,b); // apple banana
// 如果變數名與屬性名不一致,必須寫成下面這樣
let obj = {first:'hello',last:'world'};
// first ---> f,那麼此時f就是first,而不是undefined了,有點類似別名的概念
let {first:f,last} = obj;
console.log(f,last); // hello world
//1.也就是說,物件的解構賦值的內部機制,是先找到同名屬性,然後再賦給對應的變數。 真正被賦值的是後者,而不是前者
//2.v是匹配的模式,n才是變數。真正被賦值的是變數n,而不是模式v。
//注意,採用這種寫法時,變數的宣告和賦值是一體的
// v ---> n,那麼此時n就是vue,而不是undefined了
var {v:n} = {v:'vue',r:'react'};
console.log(n); // vue
console.log(v); // Uncaught ReferenceError: v is not defined
console.log(r); // Uncaught ReferenceError: r is not defined
複製程式碼
5.set和map
有待完善
es6新增的兩種資料結構
filter: 過濾掉不符合條件的元素
forEach: 遍歷
reduce: 彙總
6.箭頭函式
改變了this指向,使this指向當前呼叫的物件,簡化了函式書寫的方式:
let a = {
name: 'wjb',
fn: function(){
return this.name
}
}
a.fn()
// wjb
let a = {
name: 'wjb',
fn: () =>{
return this.name
}
}
a.fn()
// undefined
複製程式碼
常用形式:
//箭頭函式寫法 function(){} 變為 ()=>{}
window.onload = () => {
var oBox = document.getElementById("box");
oBox.onclick = () => {
oBox.style.backgroundColor = '#ff0000';
};
};
//注意this指向會有問題
var json = {
a:1,
b:2,
showName:() => {
return this.a;
}
};
// 因為使用了箭頭函式this指向了object window 所以result:undefined
console.log(json.showName());
複製程式碼
7. class類和extends
es6新增了類的概念,即像C,Java一樣宣告類,在class類中定義方法和屬性。
//傳統物件導向寫法
function Person(name,age){ // 類、建構函式
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
return this.name;
};
Person.prototype.showAge = function(){
return this.age;
};
//ES6物件導向寫法
class Person{
// 構造器(在構造器中也可以設定預設引數)
constructor(name='default',age=10){
this.name = name;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
//物件導向class給預設值
class Person{
// 構造器
constructor(name='default',age=0){
this.name = name;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
複製程式碼
js實現繼承的方式有很多種,本文主要講解原型繼承以及類繼承
原型繼承: 通過指定物件的prototype屬性,來繼承目標建構函式的方法和屬性。
類繼承 : 通過es6提供的extends方法來實現類的繼承。
如下所示:
//傳統寫法原型繼承
function Person(name,age){ // 類、建構函式
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
return this.name;
};
Person.prototype.showAge = function(){
return this.age;
};
// 工人類
function Worker(name,age){
// 屬性繼承過來
Person.apply(this,arguments);
}
// 原型繼承
Worker.prototype = new Person();
var p1 = new Person('allen',28);
var w1 = new Person('worker',1000);
console.log(w1.showName()); // 確實繼承過來了 result:worker
//ES6中物件導向實現類繼承
class Person{
// 構造器
constructor(name,age){
this.name = name;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
class Worker extends Person{
constructor(name,age,job='拖地的'){
// 繼承超父類的屬性
super(name,age);
this.job = job;
}
showJob(){
return this.job;
}
}
var p1 = new Person('aaa',18);
var w1 = new Person('www',36);
var w2 = new Worker('wwwwwwww',90);
console.log(w1.showName()); // www
console.log(w2.showJob()); // 預設給的值 ‘拖地的’
複製程式碼
8. promise
promise主要是用來解決非同步操作,它存在三種狀態: peding(等待),fulfilled(已完成),rejected(已拒絕),關於promise的用法,需要注意:
- 一個promise的狀態只可能從“等待”轉到“完成”態或者“拒絕”態,不能逆向轉換,同時“完成”態和“拒絕”態不能相互轉換
- promise必須實現then方法(可以說,then就是promise的核心),而且then必須返回一個promise,同一個promise的then可以呼叫多次,並且回撥的執行順序跟它們被定義時的順序一致
- then方法接受兩個引數,第一個引數是成功時的回撥,在promise由“等待”態轉換到“完成”態時呼叫,另一個是失敗時的回撥,在promise由“等待”態轉換到“拒絕”態時呼叫。同時,then可以接受另一個promise傳入,也接受一個“類then”的物件或方法,即thenable物件。
//基本用法
let p = new Promise((resolve, reject) => {
$.ajax({
url: '1.txt',
dataType: 'json',
success(json){
resolve(json);
},
error(err){
reject(err);
}
})
});
p.then(json=>{
console.log('成功',json);
}, err=>{
console.log('獲取失敗');
})
複製程式碼
promise.all
Promise.all可以將多個Promise例項包裝成一個新的Promise例項。同時,成功和失敗的返回值是不同的,成功的時候返回的是一個結果陣列,而失敗的時候則返回最先被reject失敗狀態的值。
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promse.reject('失敗')
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 失敗了,打出 '失敗'
})
複製程式碼
promise.race
將多個promise實列打包成一個新的實列傳送,並返回獲得結果最快的回撥。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 開啟的是 'failed'
})
複製程式碼
更多的promise訪問 www.jianshu.com/p/7e60fc1be…
9.async/await
在進行非同步請求時,往往會存在一個請求裡巢狀著多個請求,後續的請求需要用到之前的請求回撥,當請求巢狀過多時,則會出現回撥地獄,不利於程式碼的開發和維護,因此需要使用async/await來處理巢狀非同步請求。
let value
getInfo(){
let promise = new Promise(function(resolve,reject){
resolve('成功了');
});
promise.then(function(res){
return res
}).catch(function(err){
return err
});
}
ajax(){
getInfo().then((res)=>{
value = res //2-後執行
})
console.log(res) //1-先執行
}
ajax() // undefined
複製程式碼
使用async/await後
let value
getInfo(){
let promise = new Promise(function(resolve,reject){
resolve('成功了');
});
promise.then(function(res){
return res
}).catch(function(err){
return err
});
}
async ajax(){
await getInfo().then((res)=>{
value = res //1-回撥限制性
})
console.log(res) //2-後執行
}
ajax() // res
複製程式碼
10. export和import
export用於對外輸出本模組(一個檔案可以理解為一個模組)變數的介面
import用於在一個模組中載入另一個含有export介面的模組。
也就是說使用export命令定義了模組的對外介面以後,其他JS檔案就可以通過import命令載入這個模組(檔案)。
export和export default的區別
- export與export default均可用於匯出常量、函式、檔案、模組等
- 你可以在其它檔案或模組中通過import+(常量 | 函式 | 檔案 | 模組)名的方式,將其匯入,以便能夠對其進行使用
- 在一個檔案或模組中,export、import可以有多個,export default僅有一個
- 通過export方式匯出,在匯入時要加{ },export default則不需要
let name1="李四";
let name2="張三";
export { name1 ,name2 } //匯出
//匯入
import { name1 , name2 } from "/.a.js" //路徑根據實際情況填寫
let name="李四";
export default name
import name from "/.a.js" 這裡name不需要大括號
複製程式碼