ES6知识点总结
一些ES6新增的知识点,非全部,主要是不熟悉且常用的。
1. let和const
let 块级作用域造成的暂时性死区,let声明的变量在块内不仅不提升而且块内也不受外部影响,
而且使用typeof也会报Uncaught ReferenceError: Cannot access 'temp' before initialization,代码不会继续执行了。
此时typeof也会变得不安全了,但是对从未声明过的变量typeof时却不会报错
1 var temp = 123; 2 if (true) { 3 console.info(temp) //Uncaught ReferenceError: Cannot access 'temp' before initialization 4 let temp = 456 5 }
注:在es5时代没有块级作用域,如果有全局变量,花括号内(非函数)在变量声明前使用的时全局变量,"局部变量"只是对已有变量的重新赋值:
1 var temp = 123; 2 if(true){ 3 console.info(temp) // 123 4 var temp = 456 5 console.info(temp) // 456 6 } 7 console.info(temp) // 456
而在函数内部则会提升,在声明前使用局部变量其值为undefined:
1 var temp = 123; 2 function fn(){ 3 console.info(temp) // undefined 4 var temp = 456 5 } 6 fn() 7 console.info(temp) // 123
let 要点就是不提升、暂时性死区、块级作用域、不允许重复声明
const 声明时必须初始化,不允许改变值(本质是不允许改变变量指向的内存地址,所有引用类型就不能控制不该更改了)
另外引入全局对象globalThis,可以在任何位置拿到
1 console.info(globalThis === window) // true
2.变量解构赋值
声明变量时通过解构方式赋初始值,可以用数组或对象给变量提供默认值,可以不完全结构;
字符串也可以结构为单个字符;
函数参数的解构等;
3.对字符串的一些扩展
3.1 增加遍历器接口
也就是可以使用for of:
1 for (let c of 'world') { 2 console.info(c) 3 }
3.2 引入模板字符串
用反引号(`)标识
可以多行字符串
可以在字符串中嵌入变量
3.3 新增方法
includes、startWith / endsWith、repeat、padStart / padEnd
4. 正则扩展
具名组名
5.对数值的扩展
5.1Number上新增方法
Number上增加Number.isFinite()、Number.isNaN()、Number.isInterger()、Number.EPSILON(极小值,JS的精度)
Number.isSafeInterger()
将全局方法parseInt()和parseFloat,移植到Number对象上面
5.2 对Math对象的一些扩展
Math.trunc() --去掉小数部分
Math.sign() --判断符号,返回 1、-1、0、-0、NaN
Math.cbrt() --计算立方根
6.对数组的扩展
增加fill、find、findIndex、entries()、keys()、values()
includes()
flat(n) -- 将嵌套数组展开,n参数为展开层数,可用Infinity
7.函数的扩展
7.1 新变化
可以使用默认参数,rest参数,函数内部使用strict严格模式,增加name属性;
参数可以使用尾逗号,和数组与对象一致;
catch可以省略()及参数
7.2 箭头函数
简洁,简化回调函数
8.对象扩展
8.1 简洁表示方式
允许大括号内直接使用变量和函数;
可以使用...扩展运算符,将对象的属性拷贝到当前对象中;
1 let user = { 2 name: 'xcvu', 3 age: 27 4 } 5 // ES5判断一个对象的某属性是否存在,需要逐层判断 6 user && user.hobby && user.hobby.sleep || 'default' 7 // ES6可以这样写 8 console.info(user?.name || 'pig') 9 console.info(user?.hobby?.sleep || 'yes')
null 判断运算符 ??
1 // 使用 || 判断时属性值为false就会使用默认值,这样不能输出0、false 2 console.info(obj.a || 'a ||') // a || 3 console.info(obj.b || 'b ||') // b || 4 console.info(obj.c || 'c ||') // c || 5 console.info(obj.d || 'd ||') // d || 6 // 使用 ?? 判断时属性值为null或undefined时才会使用默认值,这样可以能输出0、false 7 console.info(obj.a ?? 'a ??') // fasle 8 console.info(obj.b ?? 'b ??') // 0 9 console.info(obj.c ?? 'c ??') // 注:输出为空格 10 console.info(obj.d ?? 'd ??') // d ??
8.2 对象新增方法
增加了Object.is() 严格相等 ===
Object.assign(target, source1, source2) 合并对象,浅拷贝(source的某属性为对象是,target得到的是引用),同名属性替换。
Object.keys()、Object.values()、Object.entries()
Object.fromEntries()从键值对数组创建对象;
super关键字指向原型对象
9.Symbol
独一无二的值,是 JavaScript 语言的第七种数据类型,前六种是:undefined
、null
、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol作为属性名时不能通过for...in、for...of遍历,也不能通过Object.keys()、Object.getOwnPropertyNames获取到。
可以通过Object.getOwnPropertySymbols()方法获取所有的Symbol属性名
10. Set和Map
10.1 Set
类似数组,但值不会重复
1 let s = new Set([4, 5, 6]) 2 s.add(1) 3 s.add(2) 4 s.add(1) 5 console.info(s) // {4, 5, 6, 1, 2} 6 console.info(s.has(1)) // true 7 console.info(s.size) // 5 8 s.delete(2) 9 s.clear() 10 console.info(s.size) // 0 11 // 可以使用keys(),values(),entries(), forEach() 12 13 let arr = [...new Set([1, 2, 3, 4, '3', 2])] // 数组去重, 用严格相等===判断重复 14 console.info(arr) // [1, 2, 3, 4, "3"] 15 let str = 'asdfasdfredc' 16 str = [...new Set(str)].join('') // 字符串去重 17 console.info(str) // asdfrec
WeakSet 可以接受一个数组或类似数组的对象作为参数,对象为弱引用,不能遍历,不会造成内存泄漏。
10.2 Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
1 const fn = function(){} 2 const m = new Map().set(1, 'a').set(undefined, 'nah').set(fn, 'func') 3 console.info(m.get(fn)) // func 4 console.info(m.has(fn)) // true 5 console.info(m.size) // 3 6 // delete,clear,keys(),values(),entries(), forEach() 7 8 // 扩展运算符(...)转为数组 9 let arr = [...m] 10 let obj = {"a":1, "b":2}; 11 let map = new Map(Object.entries(obj)); // 对象转map
WeakMap不能遍历,无size属性,只接受对象作为键名(null除外),不会造成内存泄漏。
11. 遍历器Iterator
是一种接口,为各种不同的数据结构提供统一的访问机制,主要供for..of使用
。
Array、Map、Set、String、TypedArray类型化数组、函数的Arguments参数、NodeList默认具有Iterator接口,对象默认没有Iterator接口
12. Generator、Promise、Async/Await
generator
用*表示函数为generator函数,内部用yield暂停代码的执行,调用时通过next()恢复执行,可以用来实现异步编程。
1 function * generator(){ 2 console.info('foo') 3 let x = yield console.info('yield 1') // 第一次调用next()方法会执行到yield后面的语句 4 console.info('x:' + x) // yield语句的返回值是下一个next()中传递的参数 5 let y = yield 'b' // yield后面的值是 next()方法得到的返回值中的value,需要注意不是yield语句的返回值(yield语句赋值给变量的值) 6 console.info('y:' + y) 7 let z = yield 'c' 8 console.info('z:' + z) 9 return 'xxxx' 10 } 11 let g = generator() 12 console.info(g.next()) // { value: undefined, done: false } 13 console.info(g.next(123)) // yield语句后的值为next方法得到的返回值的value { value: 'b', done: false } 14 console.info(g.next(46)) // next方法传递的参数是上一个yield语句的返回值 15 console.info(g.next(78)) 16 console.info(g.next(6)) // 执行完所有的yield语句后 done为true { value: undefined, done: true }
promise
Promise接受一个函数作为参数,这个函数有两个参数:resolve和reject。
resolve和reject也是函数,它们由Promise提供。
resolve函数将Promise对象的状态从pending变为resolved,在异步操作成功时调用,将异步操作结果作为参数传递出去;
reject函数将Promise对象的状态从pending变为rejected,在异步操作失败时调用,将异步操作报出的错误作为参数传递出去。
then方法:
Promise实例生成之后,可以使用then方法分别指定resolved和rejected状态的回调函数,
then方法接收两个回调函数,
第一个回调函数是Promise对象的状态变为resolved时调用,(也就是resolve函数调用之后调用,接收Promise传递出来的参数)
第二个回调函数是Promise对象的状态变为rejected时调用
Promise新建后就会立即执行:
Promise会立即执行所以先输出‘I am in Promise’,
而then方法指定的回调会在所有同步任务执行完之后才执行。
Promise的结果可以多次获得。
async / await
是promise的语法糖
1 async function getUser() { 2 let user = await fetchUser() 3 retrun user 4 } 5 6 const user = getUser() 7 console.log(user)
下面是一个完整的async/await 封装异步请求的示例:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>async / await</title> 7 </head> 8 <body> 9 10 </body> 11 <script> 12 let url = 'https://api.github.com/repos/github/hub/git/ref/heads/2.7-stable' 13 // 1.回调函数版 14 function ajaxData(url, callback){ 15 let xhr = new XMLHttpRequest() 16 xhr.open('GET', url) 17 xhr.send() 18 xhr.onreadystatechange = () => { 19 if(xhr.readyState == 4){ 20 if(xhr.status >= 200 && xhr.status < 304){ 21 callback(xhr.response) 22 } 23 } 24 } 25 } 26 ajaxData(url, (data)=>{ 27 console.info(data) 28 }) 29 30 // 2.promise版 31 function ajaxDataPromise(url){ 32 return new Promise((resolve, reject)=>{ 33 let xhr = new XMLHttpRequest() 34 xhr.open('GET', url) 35 xhr.send() 36 xhr.onreadystatechange = () => { 37 if(xhr.readyState == 4){ 38 if(xhr.status >= 200 && xhr.status < 304){ 39 resolve(xhr.response) 40 } 41 } 42 } 43 xhr.onerror = () => { 44 reject(xhr.status) 45 } 46 }) 47 } 48 ajaxDataPromise(url).then((value) => { 49 console.info(value) 50 }) 51 52 // 2.1 使用fetch简化的promise版 53 // 因为fetch返回的是promise对象 54 function fetchData(url){ 55 return fetch(url) 56 .then(response => response.json()) 57 } 58 59 fetchData(url).then(value => { 60 console.info(value.object.sha) 61 }) 62 63 // 3. async / await 版 64 // await必须放在async函数中,不能直接将结果返回,因为是一个promise对象 65 async function getDataAsync(url) { 66 let result = await fetch(url).then(response => response.json()) 67 console.info(result) 68 console.info(result.object.sha) 69 } 70 getDataAsync(url) 71 </script> 72 </html>