ES6
ES6简介
let和const
let 声明变量没有变量提升
let 是一个块作用域,let
声明的变量只在它所在的代码块有效。在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)
let 不可以重复声明
const 声明常量,一旦声明就不能被修改,除此之外也有 let 的三个特性。
开发中,默认情况下用 const,而只有在你知道变量值需要被修改的情况下使用 let
模板字符串
模板字符串:使用 tab 键的反引号 `
插入变量时:使用 ${ 变量名 }
1 2 3 4 5 6 7 8 9 10 const oBox = document .querySelector('.box' )let id = 1 , name = '牛肉粉' ;let htmlStr = `<ul> <li> <p id = ${id} > ${name} </p> </li> </ul>` oBox.innerHTML = htmlStr;
函数默认值和剩余参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function add (a = 10 , b = 20 ) { return a + b; } console .log(add()); function add (a, b = getVal(5 ) ) { return a + b; } function getVal (val ) { return val + 5 ; } console .log(add(10 ));
剩余参数 :由…和一个紧跟着的具名参数组成 : …keys
1 2 3 4 5 function checkArgs (...args ) { console .log(args); console .log(arguments ); } checkArgs('a' ,'b' ,'c' );
扩展运算符 剩余参数与扩展运算符的区别:
剩余参数:把多个独立的合并到一个数组中
扩展运算符:将一个数组分割,并将各个项作为分离的参数传给函数
1 2 3 4 const arr = [10 , 20 , 50 , 30 , 90 , 100 , 40 ];console .log(Math .max(...arr))
箭头函数
使用 => 来定义 , function(){} 等价于 () => {} ,代码变得更加简洁
箭头函数内部没有 arguments
箭头函数不能使用 new 关键字来实例化对象,function 函数也是一个对象,但是箭头函数不是
1 2 3 4 5 6 7 8 9 let add = function (a, b ) { return a + b; } let add = (a, b ) => { return a + b; }
this指向
箭头函数没有this的指向,箭头函数内部的this值只能通过查找作用域链来确定
解构赋值
解构赋值是对赋值运算符的一种扩展。它通常针对数组和对象进行操作。
优点:代码书写简洁且易读性高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 let node = { type :'iden' , name :'foo' } let {type,name} = node;console .log(type,name) let {a,...res} = obj;console .log(a,res);let {a,b = 30 } = {a :20 }; let [a, b] = [1 , 2 , 3 ];console .log(a,b) let [a, [b], c] = [1 , [2 ], 3 ]
对象扩展
**Object.is()**: 比较两个值是否严格相等
1 2 3 4 console .log(NaN === NaN )console .log(+0 === -0 )console .log(Object .is(NaN , NaN ))console .log(Object .is(+0 , -0 ))
1 2 let obj = Object .assign({}, {a :1 }, {b :2 })console .log(obj)
Symbol类型
它表示的是独一无二的值
最大的用途:用来定义对象的私有变量
如果用 Symbol 定义的是对象中的变量,取值时一定要用 [变量名]
如果用 Symbol 定义的是对象中的变量,该变量不能作为key,无法用 for 循环遍历
1 2 3 4 5 6 7 8 9 10 11 12 const name1 = Symbol ('name' )const name2 = Symbol ('name' )console .log(name1 === name2)let s1 = Symbol ('s1' )let person = { [s1]: 'qwe' } console .log(person[s1])
Set和Map Set 集合:表示无重回复值的有序列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let set1 = new Set ()set1.add(1 ) set1.add('1' ) console .log(set1)console .log(set1.size)set1.delete('1' ) console .log(set1.has('1' ))set1.add(2 ) set1.add(3 ) set1.add(4 ) for (let k of set1){ console .log(k) } let set2 = new Set ([1 ,2 ,3 ,3 ,3 ,4 ])console .log(set2)let arr = [...set2]console .log(arr)
Map:键值对的有序列表,键和值是任意类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 let map1 = new Map ()map1.set('name' , '张三' ) console .log(map1)console .log(map1.get('name' ))map1.delete('name' ) console .log(map1.has('name' ))map1.set(['a' , [1 , 2 , 3 ]], 'asd' ) console .log(map1)let map2 = new Map ([['a' , 1 ], ['b' , 2 ]])console .log(map2)
数组的扩展方法
Array.from()
方法用于将伪数组转为真正的数组
1 2 3 4 5 6 7 8 9 10 11 12 function add ( ) { let arr1 = Array .from(arguments ) console .log(arr1) } add(1 ,2 ,3 ) let lis = document .querySelectorAll('li' )let arr = Array .from(lis)console .log(arr)let arr2 = Array .from(lis, ele => ele.textContent)console .log(arr2)
1 2 let arr3 = Array .of(1 , 2 , '3' , [1 , 2 ], {id :1 })console .log(arr3)
copyWithin(target, start = 0, end = this.length); 在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组
target(必需):从该位置开始替换数据。如果为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
这三个参数都应该是数值,如果不是,会自动转为数值。
1 2 let arr4 = [1 ,2 ,3 ,8 ,9 ,10 ].copyWithin(0 , 3 )console .log(arr4)
1 2 3 4 5 let num = [1 ,2 ,-10 , 8 , -1 ].find( n => n < 0 )console .log(num)let numIndex = [1 ,2 ,-10 , 8 , -1 ].findIndex( n => n < 0 )console .log(numIndex)
ES6 提供三个新的方法——entries()
,keys()
和values()
——用于遍历数组。它们都返回一个遍历器对象,可以用for...of
循环进行遍历,唯一的区别是:
keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 let arr5 = [1 , 2 , 4 , 7 , 3 ]console .log(arr5.keys())for (let k of arr5.keys()){ console .log(k) } for (let v of arr5.values()){ console .log(v) } for (let [k, v] of arr5.entries()){ console .log(k, v) }
1 console .log(arr5.includes(5 ))
Iterator遍历器
遍历器(Iterator)它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员),快捷的访问数据。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for…of 循环,Iterator 接口主要供for…of消费。
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
第一次调用指针对象的next
方法,可以将指针指向数据结构的第一个成员。
第二次调用指针对象的next
方法,指针就指向数据结构的第二个成员。
不断调用指针对象的next
方法,直到它指向数据结构的结束位置。
每一次调用next
方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value
和done
两个属性的对象。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
1 2 3 4 5 6 7 let items = ['one' , 'two' , 'three' ];let ite = items[Symbol .iterator]();console .log(ite.next()) console .log(ite.next()) console .log(ite.next()) console .log(ite.next())
Generator函数(生成器)
Symbol.iterator
方法,等于该对象的遍历器生成函数,调用该函数会返回一个遍历器对象。而 Generator 函数也是遍历器生成函数,可以把 Generator 函数赋值给对象的Symbol.iterator
属性,从而使得该对象具有 Iterator 接口,给不具备 Iterator 接口的数据结构(不自带Symbol.iterator
方法)提供遍历操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function * fun ( ) { console .log('one' ) yield 'one' console .log('two' ) yield 'two' } let fn = fun()console .log(fn)console .log(fn.next())console .log(fn.next())console .log(fn.next())console .log("****************" )function * add ( ) { console .log('one ' ) let x = yield 'one' console .log('two ' + 'x:' + x) let y = yield 'two' console .log('add ' + 'y:' + y) return x + y } let fn2 = add()console .log(fn2.next())console .log(fn2.next(10 ))console .log(fn2.next(30 ))
使用场景:为不具备 Iterator 接口的对象提供了遍历操作
利用for...of
循环,可以写出遍历任意对象(object)的方法。原生的 JavaScript 对象没有遍历接口(不具备 Symbol.iterator
方法),无法使用for...of
循环,通过 Generator 函数为它加上这个接口,即将 Generator 函数加到对象的Symbol.iterator
属性上面,就可以用了。
除了for...of
循环以外,扩展运算符(...
)、解构赋值和Array.from
方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 let person = { name : '张三' , age : 12 , address : 'China' } function * ObjectEntries (obj ) { const propKeys = Object .keys(obj) for (const propKey of propKeys){ yield [propKey, obj[propKey]] } } for (let [k, v] of ObjectEntries(person)){ console .log(k, v) } console .log(...ObjectEntries(person)) console .log("************" ) function * ObjectEntries2 ( ) { const propKeys = Object .keys(this ) for (const propKey of propKeys){ yield [propKey, this [propKey]] } } person[Symbol .iterator] = ObjectEntries2 for (let [k, v] of person){ console .log(`${k} ${v} ` ) } console .log(...person) console .log({name, age, address} = person)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function * load ( ) { loadUI() yield showData() hideUI() } let iteload = load()iteload.next() function loadUI ( ) { console .log('加载loading...页面' ) } function showData ( ) { setTimeout (() => { console .log('数据加载完成' ) iteload.next() }, 1000 ); } function hideUI ( ) { console .log('隐藏loading...页面' ) }
Promise对象
对象的状态不受外界影响。有三种状态:pending
(进行中)、fulfilled
(成功)和rejected
(失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为resolved和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果
Promise对象是一个构造函数,用来生成Promise实例,带有一个回调函数,回调函数的两个参数是 resolve(成功) 和 reject(失败),
这两个参数他们也是函数。
then
方法的第一个参数是resolved
状态的回调函数,第二个参数是rejected
状态的回调函数,它们都是可选的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let pro = new Promise (function (resolved, rejected ) { let res = { code : 201 , data : { name : 'asd' }, error : '失败了' } setTimeout (() => { if (res.code === 200 ){ resolved(res.data) }else { rejected(res.error) } }, 1000 ) }) console .log(pro) pro.then((val ) => { console .log(val) }, (err ) => { console .log(err) })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function timeOut (ms ) { return new Promise (function (resolved, rejected ) { let res = { code : 200 , data : { name : 'asd' }, error : '失败了' } setTimeout (() => { if (res.code === 200 ){ resolved(res.data) }else { rejected(res.error) } }, ms) }) } timeOut(2000 ).then((val ) => { console .log(val) })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const getJSON = function (url ) { return new Promise ((resolve, reject ) => { const xhr = new XMLHttpRequest() xhr.open('GET' , url) xhr.responseType = 'json' xhr.setRequestHeader('Accept' , 'application/json' ) xhr.send() xhr.onreadystatechange = handler function handler ( ) { if (this .readyState === 4 ){ if (this .status === 200 ){ resolve(this .response.HeWeather6) }else { reject(new Error (this .statusText)) } } } }) } let a = getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976' ) .then((data ) => { console .log(data[0 ]) }).catch((err ) => { console .log(err) })
如果一个promise执行完后 返回的还是一个promise 实例(注意,不是原来那个Promise
实例),会把这个promise 的执行结果,传递给下一次then
中。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
catch(err=>{})
方法等价于then(null,err=>{}),
用于指定发生错误时的回调函数
resolve()
方法将现有对象转换成Promise对象,该实例的状态为 fulfilled 成功
1 2 3 4 5 6 let p = Promise .resolve('foo' )console .log(p)p.then((data ) => { console .log(data) })
reject()
方法和resolve()
方法一样返回一个新的Promise实例,该实例的状态为 rejected(失败)
1 2 3 4 5 let p2 = Promise .reject(new Error ('出错了' ));p2.catch(err => { console .log(err); })
1 2 3 4 5 6 7 8 9 10 11 12 let p1 = new Promise (resolve => resolve())let p2 = new Promise (resolve => resolve())let p3 = new Promise (resolve => resolve())let p4 = Promise .all([p1, p2, p3])p4.then(() => { }).catch(() => { })
Promise.all()接受一个promise对象的数组,待全部完成之后,统一执行success ;
race(): 接受一个包含多个promise对象的数组,只要有一个完成,就执行success
应用:当我们请求某个图片资源,会导致时间过长,给用户反馈
用race给某个异步请求设置超时时间,并且在超时后执行相应的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function requestImg (ImgSrc ) { return new Promise ((resolve, reject ) => { const img = new Image() img.onload = function ( ) { resolve(img) } img.src = ImgSrc }) } function timeout ( ) { return new Promise ((resolev, reject ) => { setTimeout (() => { reject(new Error ('请求图片失败' )) }, 3000 ) }) } Promise .race([requestImg('' ), timeout()]).then((data ) => { console .log(data) }).catch((err ) => { console .log(err) }).done(() => { })
async异步操作 async 函数,它就是 Generator 函数的语法糖
作用:使得异步操作更加方便
凡是在前面添加了async的函数在执行后都会自动返回一个Promise对象
1 2 3 4 5 6 async function test ( ) { } let result = test()console .log(result)
await必须在async函数里使用,不能单独使用
await的作用之一就是获取后面Promise对象成功状态传递出来的参数传给 then 函数。
1 2 3 4 5 6 7 8 9 async function f ( ) { return await 'hello async' ; } f().then(v => {console .log(v)}).catch(e => {console .log(e)});
如果 async 函数中有多个 await , 那么 then 函数 会等待所有的 await 指令运行完才去执行
1 2 3 4 5 6 async function f ( ) { let s = await 'hello world' let data = await s.split('' ); return data; } f().then(v => {console .log(v)}).catch(e => {console .log(e)});
任何一个await
语句后面的 Promise 对象变为reject
状态,那么整个async
函数都会中断执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 async function f ( ) { await Promise .reject('出错了' ); await Promise .resolve('hello' ); } f().then(v => {console .log(v)}).catch(e => {console .log(e)}); async function f2 ( ) { await new Promise (function (resolve, reject ) { throw new Error ('出错了' ); }); } f2().then(v => console .log(v)).catch(e => console .log(e))
针对上诉遇到 reject
状态,就中断执行的问题,可以通过 try…catch 代码块解决
1 2 3 4 5 6 7 8 9 10 11 async function f ( ) { try { await Promise .reject('出错了' ); } catch (error){ } return await Promise .resolve('hello' ); }); } f2().then(v => console .log(v)).catch(e => console .log(e))
class的用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Person { constructor (name, age ) { this .name = name; this .age = age; } sayName ( ) { return this .name; } sayAge ( ) { return this .age; } } let p = new Person('牛肉粉' ,18 );console .log(p);p.sayName(); p.sayAge();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Animal { constructor (name, age ) { this .name = name; this .age = age; } sayName ( ) { return this .name; } sayAge ( ) { return this .age; } } class Dog extends Animal { constructor (name, age, color ) { super (name, age); this .color = color; } sayColor ( ) { return `${this .name} 是${this .age} 岁了,它的颜色是${this .color} ` ; } sayName ( ) { return this .name + super .sayAge + this .color; } } let d1 = new Dog('小黄' , 28 , 'red' );console .log(d1.sayAge()); console .log(d1.sayColor()); console .log(d1.sayName());
模块化
ES6 模块功能主要有两个命令构成:export 和 import
export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export const name = '张三' ;export const age = 18 ;export const sayName = function ( ) { console .log(fristName); } const name = '张三' ;const age = 18 ;const sayName = function ( ) { console .log(fristName); } export {name, age, sayName}
1 2 import {name, age, sayName} from './modules/index.js' ;
使用export default
命令为模块指定默认输出,在其它模块加载该模块时,import
命令可以为该匿名函数指定任意名字
1 2 3 4 5 6 7 8 9 10 11 export default function ( ) { console .log('foo' ); } function foo ( ) { console .log('foo' ); } export default foo;
如果想在一条import语句中,同时输入默认方法(default)和其他接口(非default),可以写成下面这样
1 2 3 4 5 6 7 8 export default function ( ) { console .log('foo' ); } export function add ( ) { console .log('add' ) }
1 2 3 4 5 6 import customName,{add} from 'export-default.js' import * as f from 'export-default.js' console .log(f); console .log(f.default);
export default
也可以用来输出类
1 2 3 4 5 6 export default class Person { ... } import Person from 'MyClass' ;let o = new Person();
数组方法 ES5
indexof(): 用于查找数组中是否存在某个值,如果存在则返回某个值的下标,否则返回-1
1 2 3 4 let list = [1 , 2 , 3 ];console .log(list.indexOf(2 )) console .log(list.indexOf("蛙人" ))
map():map
是一个数组函数方法,接收三个参数,value
,index
,self
,返回值是处理完的结果,返回新数组。
1 2 3 4 5 6 7 8 9 let list = [1 , 2 , 3 ];const res = list.map((value, key, self ) => { console .log(value) console .log(key) console .log(self) return value * 2 }) console .log(res)
foreach():用于遍历一个数组,接收三个参数,value
,index
,self
,返回值为undefined
1 2 3 4 5 6 7 8 9 let list = [1 , 2 , 3 ];const res = list.forEach((value, key, self ) => { console .log(value) console .log(key) console .log(self) return 123 }) console .log(res)
splice(): 用于数组删除或替换内容,接收三个参数:
第一个参数是,删除或添加的位置
第二个参数是,要删除的几位,如果为0则不删除
第三个参数是,向数组添加内容
1 2 3 4 5 6 7 8 9 10 let list = [1 , 2 , 3 ];list.splice(0 , 1 ) console .log(list) list.splice(0 , 1 , "蛙人" ) console .log(list) list.splice(0 , 2 , "蛙人" ) console .log(list)
slice():用于截取数组值,接收两个参数,第一个参数是要获取哪个值的下标,第二个参数是截取到哪个下标的前一位。
1 2 3 4 let list = [1 , 2 , 3 ];let res = list.slice(1 , 3 ) console .log(res)
filter():用于过滤数组内的符合条件的值,返回值为满足条件的数组对象
1 2 3 4 let list = [1 , 2 , 3 ];let res = list.filter(item => item > 1 );console .log(res)
every():用于检测数组所有元素是否都符合指定条件,返回值为Boolean
, 该方法是数组中必须全部值元素满足条件返回true
,否则false
1 2 3 4 5 6 7 let list = [1 , 2 , 3 ];let res = list.every(item => item > 0 )console .log(res) let res1 = list.every(item => item > 1 )console .log(res1)
some():用于检测数组中的元素是否满足指定条件,返回值为Boolean
, 该方法是只要数组中有一项满足条件就返回true
,否则false
1 2 3 4 let list = [1 , 2 , 3 ];let res = list.some(item => item > 0 )console .log(res)
1 >reduce(function (previousValue, currentValue, currentIndex, array ) { }, initialValue)
callbackFn
一个“reducer”函数,包含四个参数:
previousValue
:上一次调用 callbackFn
时的返回值。在第一次调用时,若指定了初始值 initialValue
,其值则为 initialValue
,否则为数组索引为 0 的元素 array[0]
。
currentValue
:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue
,其值则为数组索引为 0 的元素 array[0]
,否则为 array[1]
。
currentIndex
:数组中正在处理的元素的索引。若指定了初始值 initialValue
,则起始索引号为 0,否则从索引 1 起始。
array
:用于遍历的数组。
initialValue
可选
作为第一次调用 callback
函数时参数 previousValue 的值。若指定了初始值 initialValue
,则 currentValue
则将使用数组第一个元素;否则 previousValue
将使用数组第一个元素,而 currentValue
将使用数组第二个元素。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
pop() 删除并返回数组的最后一个元素
shift() 删除并返回数组的第一个元素
reverse() 颠倒数组中元素的顺序。
1 2 3 4 5 6 7 let list = [1 , 2 , 3 ];let res = list.join("-" );console .log(res) let sum = eval (list.join("+" ))console .log(sum)
sort():可之间排序,或使用回调函数,用于将数组排序,排序规则看返回值
1 2 3 4 let list = [1 , 2 , 3 ];let sort = list.sort((a, b ) => b - a)console .log(sort)
1 2 3 4 let list = [1 , 2 , 3 ];let res = list.concat([1 , 2 , 3 ])console .log(res)
Array.isArray():检测对象是不是一个数组
1 2 3 4 let list = [1 , 2 , 3 ];let res = Array .isArray(list)console .log(res)