ES6改動很大芜果,可以簡單分為四類
1、解決原有語法的缺陷和不足
例如:let融师,const
2右钾、對原有語法進行增強
解構(gòu)、擴展旱爆、模板字符串
3舀射、新增對象、全新的方法怀伦,全新的功能
Object.assign()脆烟、Proxy對象代理、Reflect 等等
4房待、全新的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)
set邢羔、map、class桑孩、迭代器拜鹤、生成器 等等
一、解決原有語法的缺陷和不足
1流椒、let:塊級作用域署惯,沒有變量提升
用途:for循環(huán)的計數(shù)器(for循環(huán)內(nèi)部let聲明的變量同樣擁有塊級作用域);循環(huán)事件綁定不必采用閉包形式
for (let i=0; i<3; i++) {
let i = 'foo'
console.log(i)
}
2镣隶、const: 恒量/常量极谊;聲明后不能修改內(nèi)存地址,可修改屬性成員
最佳實踐:不用var安岂,主用const轻猖,配合let
二、對原有語法的增強
1域那、數(shù)組的解構(gòu):根據(jù)數(shù)組對應(yīng)的位置提取對應(yīng)的值賦給對應(yīng)的變量
let arr = [1,2,3]
let [x, y, z] = arr
如果未取到對應(yīng)的值咙边,賦值“undefined”
可以用...運算符
var [x, ...other] = arr
可以設(shè)置默認(rèn)值
var [x='0', y, z] = arr
用途:字符串截取
const str = 'http://www.baidu.com?titile=article'
var [, strParam] = str.split('?')
2猜煮、對象的解構(gòu):根據(jù)屬性名提取
const obj = {name: 'zdd', age: 18}
const { name, age } = obj
如果想換一個變量名&添加默認(rèn)值
const {name: objName='www', age} = obj
應(yīng)用場景:代碼簡化
const { log } = console
log('hh')
3、模板字符串:字符串增強
1败许、可換行
2王带、可使用插值表達式添加變量,變量也可以替換為可執(zhí)行的js語句:
let str = `生成一個隨機數(shù):${ Math.random() }`
標(biāo)簽?zāi)0遄址幸螅瑯?biāo)簽相當(dāng)于一個自定義函數(shù)愕撰,自定義函數(shù)的第一個參數(shù)是被差值表達式截取的數(shù)組
// 標(biāo)簽?zāi)0遄址? const name = 'www';
const isMan = true
const tagFn = function (strings, name, isMan) {
let sex = isMan ? 'man' : 'woman';
return strings[0] + name + strings[1] + sex + strings[2]
}
const result = tagFn`hey, ${name} is a ${isMan}.`
4、字符串的擴展方法
1醋寝、includes
2搞挣、startWith
3、endsWith
5音羞、函數(shù)參數(shù)增強:參數(shù)默認(rèn)值
只有當(dāng)參數(shù)為不傳或傳入undefined時使用默認(rèn)值
const fn = function (x=1, y) {
console.log(x)
console.log(y)
}
fn()
6囱桨、...操作符:收起剩余數(shù)據(jù)、展開數(shù)組
收取剩余參數(shù):取代arguments嗅绰,arguments是一個類數(shù)組舍肠,...操作符是一個數(shù)組類型,可以使用數(shù)組方法
1窘面、僅使用一次
2貌夕、放在參數(shù)最后
const fn = function (x, ...y) {
console.log(y.slice(0))
}
fn(1,2,3,4,5)
展開數(shù)組
const spredArr = [1,2,3,4]
console.log(...spredArr)
console.log.apply(this, spredArr) //es5代替方案
7、箭頭函數(shù):簡化寫法
箭頭函數(shù)的this指向上級作用域
const name = 'tony'
const person = {
name: 'tom',
say: () => console.log(this.name),
sayHello: function () {
console.log(this.name)
},
sayHi: function () {
setTimeout(function () {
console.log(this.name)
}, 500)
},
asyncSay: function () {
setTimeout(()=>console.log(this.name), 500)
}
}
person.say() //tony
person.sayHello() //tom
person.sayHi() //tony
person.asyncSay() //tom
8民镜、對象字面量的增強
1啡专、如果key與value變量名相同,省略:value
2制圈、省略函數(shù):function
3们童、計算屬性:[Math.random()]
const bar = 'bar'
const obj = {
bar,
fn () {
console.log('1111')
},
[Math.random()]: '123'
}
console.log(obj)
三、新增對象鲸鹦、全新的方法慧库、全新的功能
1、Object.assign():合并多個對象馋嗜,第一個參數(shù)就是最終的返回值齐板,如果對象的屬性名相同,后面的覆蓋前面的
用途:復(fù)制對象葛菇,給options屬性賦默認(rèn)值
let objA = {
a: 'aa',
b: 'bb'
}
let objB = {
b: 'dd',
c: 'ee'
}
let result = Object.assign({}, objA, objB)
result.a = 'cc'
console.log(objA, result) //{a: "aa", b: "bb"} {a: "cc", b: "dd", c: "ee"}
2甘磨、Object.is():判斷兩個值是否相等,返回布爾值
用途:es5中眯停,對于0的判斷不區(qū)分正負(fù)值济舆,-0 == +0返回true,NaN == NaN返回 返回false莺债;
Object.is()規(guī)避了這些問題
Object.is(+0, -0)//false
Object.is(NaN, NaN) //true
3滋觉、Proxy:代理對象
基本用法
const person = {
name: 'www',
age: '20'
}
const personProxy = new Proxy(person, {
get(target, key) {
return target[key] ? target[key] : 'default'
},
set(target, key, value) {
target[key] = value % 2 ? value : 99
}
})
console.log(person.xxx) // undefined
console.log(personProxy.xxx) // default
console.log(personProxy.age) //20
personProxy.age = 100
console.log(personProxy) //{name: "www", age: 99}
這里注意的一點是签夭,這里被攔截的是”personProxy“,而不是”person“
與Object.definedProperty()的比較:
1椎侠、相比與Object.definedProperty只能監(jiān)聽get,set行為第租,proxy監(jiān)聽的行為更多一些,has我纪、deleteProperty ... 等很多
2慎宾、對于數(shù)組的push,pop等操作,proxy是監(jiān)聽的整個對象的行為宣羊,所以通過set方法能夠監(jiān)聽到;而definedProperty需要指定該對象的屬性名汰蜘,對于數(shù)組來說仇冯,就是指定數(shù)組的下標(biāo),是監(jiān)聽不到數(shù)組的push,pop等操作的
let arr = []
let arrProperty = new Proxy(arr, {
set (target, key, value) {
console.log(target, key, value) //[1] "length" 1
target[key] = value
return true
}
})
arrProperty.push(1)
console.log(arrProperty) //[1]
3族操、proxy以非侵入的方式苛坚,監(jiān)聽了對象的讀寫;definedProperty需要指定具體需要監(jiān)聽對象的屬性名色难,與上面的數(shù)組類似泼舱,如果想要監(jiān)聽一個含有多個屬性的對象的讀寫行為,definedProperty需要遍歷這個對象的所有屬性
4枷莉、Reflect: 封裝操作對象的統(tǒng)一API
在之前的es5中娇昙,操作對象有很多種方式
const obj = {
name: '111',
age: '22'
}
// 判斷對象某個屬性是否存在
console.log('name' in obj)
// 刪除某個屬性
console.log(delete obj['name'])
// 獲取對象key
console.log(Object.keys(obj))
對于不同的操作行為,使用的方式卻不同笤妙,Reflect的目的是使用同一套方式去操作對象
const obj = {
name: '111',
age: '22'
}
// 判斷對象某個屬性是否存在
console.log(Reflect.has(obj,'name'))
// 刪除某個屬性
console.log(Reflect.deleteProperty(obj, 'name'))
// 獲取對象key
console.log(Reflect.ownKeys(obj))
5冒掌、用于處理異步,解決回調(diào)函數(shù)的地獄式嵌套問題
四蹲盘、全新的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)類型
1股毫、class 類
es5寫法
function People (name) {
// 設(shè)置實例屬性
this.name = name;
}
// 設(shè)置實例的共享方法
People.prototype.sayHi = function () {
console.log(this.name)
}
let p = new People('tom')
p.sayHi()
使用class更易理解,結(jié)構(gòu)清晰
class Peopel {
constructor (name) {
this.name = name
}
say () {
console.log(this.name)
}
}
const p = new Peopel('tony')
p.say()
類的繼承
class Peopel {
constructor (name) {
this.name = name
}
say () {
console.log(this.name) //tom召衔,在子類的sayAge中調(diào)用
}
}
class Worker extends Peopel {
constructor (name,age) {
super(name)
this.age = age
}
sayAge () {
super.say()
console.log(this) // Worker {name: "tom", age: 18}
console.log(this.age) // 18
}
}
const p = new Worker('tom', 18)
p.sayAge()
類的繼承還是通過原型鏈的方式實現(xiàn)铃诬,具體可以看下babel轉(zhuǎn)換后的代碼
super可以作為函數(shù)調(diào)用,也可以作為對象調(diào)用
作為函數(shù)調(diào)用時苍凛,只能在子類的constructor中調(diào)用趣席,此時執(zhí)行父類的構(gòu)造函數(shù)constructor,執(zhí)行父類構(gòu)造函數(shù)時醇蝴,this指向的是子類Worker吩坝,所以實例p會有name屬性(對于super理解的還是不夠,后面要單獨學(xué)習(xí)下)
2哑蔫、set數(shù)據(jù)結(jié)構(gòu):可以理解為集合钉寝,不重復(fù)
const s = new Set()
s.add(1).add(2).add(3)
console.log(s) //{1, 2, 3}
console.log(s.size) // 3
const arr = [1,2,3,2,4]
console.log([... new Set(arr)]) //[1,2,3,4]
3弧呐、map數(shù)據(jù)結(jié)構(gòu)
es5中的對象key只能是字符串,map的key可以是任意數(shù)據(jù)類型, 可以通過get,set,has等操作map
const m = new Map()
const tom = {name: '99'}
m.set(tom, 90)
console.log(m.get(tom))
m.forEach((value, key) => {
console.log(value, key)
})
4嵌纲、Symbol新的數(shù)據(jù)結(jié)構(gòu)俘枫,唯一值
用途:防止全局對象中,某個屬性名重名逮走,產(chǎn)生沖突鸠蚪;定義私有屬性,外部訪問不到师溅,且遍歷不到
const s = Symbol('描述')
console.log(s)
const obj = {
[Symbol('私有屬性')]: '11'
}
console.log(obj) //obj對象Symbol('私有屬性')這個屬性外部訪問不到
console.log(Object.keys(obj)) //[]
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(私有屬性)]
const s1 = Symbol.for('111')
const s2 = Symbol.for('111')
console.log(s1 === s2) //true
5茅信、for ... of 遍歷
es5中,使用for ... in 遍歷鍵值對結(jié)構(gòu)數(shù)據(jù)墓臭,使用forEach遍歷數(shù)組
es6中新增了set,map數(shù)據(jù)結(jié)構(gòu)蘸鲸,for...of是用來統(tǒng)一遍歷擁有某一種特性的數(shù)據(jù)結(jié)構(gòu)(可迭代)
const arr = [1,2,3]
for (const item of arr) {
// 遍歷數(shù)組
console.log(item)
}
const s = new Set()
s.add(1).add(2).add(3)
for (const item of s) {
// 遍歷set結(jié)構(gòu)
console.log(item)
}
const m = new Map([
['name','昵稱'],
['title', '標(biāo)題']
])
for (const [key, value] of m) {
// 遍歷map結(jié)構(gòu)
console.log(key)
console.log(value)
console.log(m.get(key))
}
const newSet = new Set([
['name','昵稱'],
['title', '標(biāo)題']
])
const newMap = new Map(newSet)
for (const [key, val] of newMap) {
// 遍歷set初始化后的map結(jié)構(gòu)
console.log(key)
console.log(val)
}
const obj = {
name: 'ttt',
age: '19'
}
for (const [key, val] of obj) {
// 遍歷對象報錯 Uncaught TypeError: obj is not iterable
console.log(key, val)
}
上面代碼中,for...of可以遍歷數(shù)組窿锉,set, map酌摇,但是卻不能遍歷對象,是因為對象沒有可迭代接口
6嗡载、可迭代接口
在瀏覽器中打印一個數(shù)組窑多,在數(shù)組的原型對象上有一個Symbol內(nèi)置屬性Symbol.iterator方法,該方法會返回一個iterator對象洼滚,該對象包含一個next()方法埂息,調(diào)用iterator.next()會返回一個迭代器結(jié)果對象iterationResult,iterationResult對象包含兩個值遥巴,value為遍歷的item耿芹,done為當(dāng)前數(shù)據(jù)是否遍歷完成
const iterator = arr[Symbol.iterator]()
console.log(iterator) // Array Iterator {}
const ite = iterator.next()
console.log(ite) //{value: 1, done: false} value為迭代器的值,done標(biāo)識是否遍歷完
由于上面代碼中obj對象不沒有Symbol.iterator的內(nèi)置方法挪哄,所以它不是一個可迭代對象吧秕,當(dāng)使用for...of遍歷時就報錯了,下面手動實現(xiàn)obj可迭代
let iteratorObj = {
//iteratorObj是可迭代對象 iterable
name: 'ttww',
age: '18',
[Symbol.iterator] () {
let index = 0;
let arr = []
for (const key in iteratorObj) {
arr.push([key, iteratorObj[key]])
}
return {
//返回的對象叫iterator
next () {
return {
//結(jié)果對象iterationResult
value: arr[index],
done: index++ >= arr.length
}
},
}
}
}
for (const [key, val] of iteratorObj) {
console.log(key, val)
}
上面代碼中迹炼,iteratorObj有了可迭代接口砸彬,認(rèn)為是可迭代對象iterable;Symbol.iterator方法返回的對象是迭代器對象iterator斯入;迭代器對象next方法返回的對象是迭代器結(jié)果對象iterationResult
6砂碉、生成器 generator
用途:處理異步調(diào)用回調(diào)嵌套的問題
function *geFn () {
console.log('111')
yield 100
console.log('222')
yield 200
console.log('333')
yield 300
}
let generator = geFn()
console.log(generator.next()) //111 {value: 100, done: false}
console.log(generator.next()) //222 {value: 200, done: false}
console.log(generator.next()) //333 {value: 300, done: false}
在函數(shù)名前面加一個"*",函數(shù)就變?yōu)樯善骱瘮?shù)刻两,執(zhí)行該函數(shù)時增蹭,里面的函數(shù)不會立即執(zhí)行,而是會返回一個生成器對象磅摹,調(diào)用生成器對象的.next方法函數(shù)開始執(zhí)行滋迈,當(dāng)遇到”yield“關(guān)鍵字霎奢,函數(shù)會停止執(zhí)行,并把yield的值當(dāng)做next方法返回對象的value; 當(dāng)下次調(diào)用next方法時饼灿,函數(shù)從當(dāng)前位置開始繼續(xù)執(zhí)行
生成器函數(shù)執(zhí)行后返回的生成器對象generator幕侠,內(nèi)部也是實現(xiàn)了迭代器接口,所以可以使用for...of來遍歷
function *geFn () {
console.log('111')
yield 100
console.log('222')
yield 200
console.log('333')
yield 300
}
let generator = geFn()
for (const item of generator) {
console.log(item)
}
可以使用生成器函數(shù)改寫上面對象的迭代器方法
let iteratorObj = {
name: 'ttww',
age: '18',
[Symbol.iterator]:function *() {
let index = 0;
let arr = []
for (const key in iteratorObj) {
arr.push([key, iteratorObj[key]])
}
// for (let i =0; i<arr.length; i++) {
// console.log(arr[i])
// yield arr[i]
// }
for (const item of arr) {
yield item
}
// arr = ['b',3,4,5]
// return {
// next () {
// return {
// value: arr[index],
// done: index++ >= arr.length
// }
// },
// }
}
}
for (const [key, val] of iteratorObj) {
console.log(key, val)
}
這里有一個注意的點就是在循環(huán)arr數(shù)組時碍彭,不能是有forEach遍歷晤硕,是因為forEach里需要傳一個回調(diào)函數(shù),這個函數(shù)不是生成器函數(shù)庇忌,在非生成器函數(shù)里使用yield關(guān)鍵字會報錯
ES2016
1舞箍、數(shù)組新增方法:includes
const arr = [1,2,3]
console.log(arr.includes(2)) //true
2、指數(shù)運算符
console.log(2 ** 10) //1024
ES2017
1皆疹、Object.values()疏橄,以數(shù)組的形式,返回對象所有的值
let obj = {
title: 'wwwww',
age: 199
}
console.log(Object.values(obj)) //["wwwww", 199]
2墙基、Object.entries()软族,以數(shù)組的形式刷喜,返回對象的所有鍵值對
let obj = {
title: 'wwwww',
age: 199
}
console.log(Object.entries(obj)) //[["title", "wwwww"],["age", 199]]
可以將對象轉(zhuǎn)為map數(shù)據(jù)結(jié)構(gòu)
let obj = {
title: 'wwwww',
age: 199
}
let m = new Map(Object.entries(obj))
console.log(m) //{"title" => "wwwww", "age" => 199}
3残制、Object.getOwnPropertyDescriptor()
獲取一個對象的完整描述信息,可用于將一個對象的get掖疮,set屬性賦值給另一個對象
let obj = {
firstName: 'abc',
lastName: '123',
get fullName () {
return this.firstName + this.lastName
}
}
console.log(obj.fullName) //abc123
const p2 = Object.assign({}, obj)
// 此時賦值給p2的僅僅是fullName屬性的值初茶,并沒有fullName屬性的getter
p2.firstName = '456'
console.log(p2.fullName) //abc123
const description = Object.getOwnPropertyDescriptors(obj)
console.log(description)
const p3 = Object.defineProperties({}, description);
p3.firstName = '789'
console.log(p3.fullName) //789123
4、字符串的padEnd()浊闪、padStart()方法
5恼布、async/await