es6

113 阅读8分钟
1. let、const、var的区别
  1. let不能重复定义
  2. let没有变量提升
  3. let有暂时性死区(声明变量前,不可用)
  4. let有块级作用域
  5. 不会挂载在window上
const和let基本一致,有一点不同,const定义的值不能改变,这里说的改变是不能改变const定义的变量的指向,内容是可以改变的

const a = {};
a.b = 1;
  1. var可以重复定义
  2. var存在变量提升
  3. var只有全局作用域、函数作用域
  4. 会挂载在window上

2.解构赋值
数组结构赋值
基本用法

let [a,b,c] = [1,2,3]
console.log(a,b,c)  //1 2 3
let [d,,] = [1,2,3]
console.log(d) // 1
let [[h],g] = [[1],2]
console.log(h,g) // 1 2
let [w,...y] = [1,2,3]
console.log(w,y)// 1 [2,3]
不完全结构

let [[a]] = [[1,2]]
console.log(a)  //1
赋值失败为undefined
let [j] = []console.log(j)//undefined
结构时赋默认值

let [a = 1,b = 2] = [3]
console.log(a,b)//2 3
let [c = 1,d = 2] = [undefined,null] 右边严格等于undefined时才用才用默认值
console.log(c,d) // 1,null
对象赋值

let {a} = {a:1}
console.log(a)  //1
嵌套使用时:

let {a:[b,{c}]} = {a:[1,{c:3}]}
console.log(b,c)//1 3
赋值失败会报错

let {g} = {a:1,b:2}
console.log(g)//报错
默认值

let {a:1,b:2} = {a:undefined,b:null}
console.log(a,b) //1 null
字符串结构

let {a,b,c,d} = 'text'
console.log(a,b,c,d) // t e x t
let {length:a} = 'text'console.log(a) //4
结构赋值的好处:
  1. 变量值交换
  2. 函数可以返回多个值
  3. 函数参数有所对应
  4. 方便提取json数据
  5. 函数传参加默认值
  6. 模块引入方法
1.值交换

let a = 1;
let b = 2;
[a,b] = [b,a]
console.log(a,b) // 2 1
2.函数返回多个值

function a(){  
  return { b:1, c:2}
}
let {b,c} = a()console.log(b,c) // 1  2
3.传参可以不按顺序

function b({c,d}){  
  console.log(c,d)
}
b({d:3,c:2})  //2  3
4.提取jsonshuju

let jsonData = {  a:1,  b:2,  c:1};
let {a,b,c} = jsonData;
5.函数传参加默认值

function c({a=1,b=2} = {}){  
  console.log(a+b);
}
c() //3
c(1,4)//5
6.模块引入方法

let {a,b} = reuire('./xx')
3.字符串的新增方法:
  1. String.fromCodePoint()
  2. String.raw()
  3. 实例方法:codePointAt()
  4. 实例方法:normalize()
  5. 实例方法:includes(), startsWith(), endsWith()
  6. 实例方法:repeat()
  7. 实例方法:padStart(),padEnd()
  8. 实例方法:trimStart(),trimEnd()
  9. 实例方法:matchAll()
String.fromCodePoint 将unicode转换成对应的字符,优化了es5中的fromCharCode不能转换大于0xFFFF的字符

String.fromCodePoint(a)  //61
String.codePointAt与String.fromCOdePoint相反,将字符转换为unicode码,可以判断一个字符由两个字节还是四个字节组成

String.codePointAt('')
String.raw 模板字符串中斜杠都被转义:

String.raw`hi\n${1+2}`  // 实际:hi\\n3,返回:hi\n3
实例方法
String.startsWith、String.endsWith, String.includes

let str = 'hello';
str.startsWith('h')  //true
str.endsWidth('o') //true
str.includes('l') //true
repeat 

'hello'.repeat(2) //hellohello
'hello'.repeat(2.8) //hellohello 向下取整
注意:不支持infinity、负数,-0.9-1之间返回0
padStart、padEnd

'a'.padStart(2,'0')  //0a
'2'.padEnd(5,'ab')   //ab222
trimStart、trimEnd

let a = ' 2 ';
a.trim() //'2'
a.trimStart() //'2 '
a.trimEnd() //' 2'

  4.数字扩展:
  1. 二进制和八进制表示法
  2. Number.isFinite(), Number.isNaN()
  3. Number.parseInt(), Number.parseFloat()
  4. Number.isInteger()
  5. Number.EPSILON
  6. 安全整数和 Number.isSafeInteger()
  7. Math 对象的扩展
  8. 指数运算符
  9. BigInt 数据类型
二进制、八进制的表示

二进制:0b/0B
八进制:0o/0O
Number.isFinite,Number.isNaN判断数据类型是否有限、是否为NaN

Number.isFinite(1) //true
Number.isFinite(true) //false
Number.isFinite(NaN) //false
Number.isFinite(infinity) //false
不是数值则为false
Number.isNaN(NaN) //true
Number.isNaN(2) //false
不是NaN则为false
Number.parseInt、Number.parseFloat将parseInt、parseFloat移植到Number上
Number.isInteger 判断是否为整数,注意Number.isInteger(5E-325)自动转成0,要求高精度则不要用Number.isInteger
Math新增方法
Math.trunc( )  取整  正数向下取整floor,负数向上取整ceil,非数字类型先转换成数字,如果转换不了返回NaN

Math.trunc(1.222)  //1
Math.trunc(-1.32) //-1
Math.trunc('-9.88') //-9
Math.trunc(NaN) //NaN
Math.trunc(null) //0
Math.trunc(undefined) //NaN
Math.trunc('aaa') //NaN
Math.trunc(true) //1
Math.teunc(false)
Math.sign 判断是正数、负数、0,非数字类型先转换成数字,如果转换不了返回NaN

Math.sign(-5) //-1
Math.sign(9) //1
Math.sign('-6') //-1
Math.sign('')//0
Math.sign(NaN)//NaN
非数字转换:x = +x

5.函数
  1. 函数参数的默认值
  2. rest 参数
  3. 严格模式
  4. name 属性
  5. 箭头函数
  6. 尾调用优化
  7. 函数参数的尾逗号
  8. Function.prototype.toString()
  9. catch 命令的参数省略
默认参数

//es5 函数不能设置默认参数
function aa(x,y){ 
  y = y || 1  
  console.log(x,y)
}
aa(1) //1,1
aa(2,'') //2,1
//存在问题,如果没有传参数,或者参数的值为空时会改变原有的值

//es6
function aa(x,y='1'){  
  console.log(x,y)
}
aa(1) // 1,1
aa(1,'') //1
//当传的参数严格等于undefined时,才会使用默认的值
//参数不能重名,参数与函数内部变量不能重名

function aa(x,x,y){
} 
function aa(x,y){  
  let x = 0;
}
//参数默认值是惰性的,使用时才会计算
//解构赋值默认值

function aa({x,y = 0}){ 
  console.log(x,y);
}
aa({}) //undefined,0aa({x:1,y:2}) //1,2aa()//报错 不能从undefined中结构出{x,y}
//参数赋默认值

function aa({x,y=2} = {}){  
  console.log(,y)
}
aa() //undefined,2
//参数默认解构的区别

// 写法一
function m1({x = 0, y = 0} = {}) {
//传参严格等于undefined时会走默认值{},解构出来又赋值了默认值,当传参有值时,
//使用参数的值如果参数只传递了x,y的值为默认值0   
   return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
//传参严格等于undefined时会走默认值{x: 0, y: 0},当传参有值时,{x,y}等于传递的参数,
如果参数只传递了x,y的值为undefined    
  return [x, y]
}
m1() //[0,0]
m2() //[0,0]

m1({x:2}) //[2,0]
m2({x:2}) //[2,undefined]
m1({}) // [0, 0];
m2({}) //[undefined,undefined]
//参数默认值的位置:最好写在末尾,如果写在开头、中间,传参时不能省略
计算函数长度时,不会计入默认参数及默认参数后面的参数

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
函数参数的作用域
rest参数(剩余参数),是真正的数组,只能放在最后,函数的length,也不计入rest

function aa(x,...args){
  console.log(args)
}
aa(1,2,3) //[2,3]
name属性

function aa(){}  //aa.name => aa
箭头函数
  1. 箭头函数没有this,里面的this指向函数定义时对象
  2. 箭头函数没有arguments
  3. 箭头函数不能当构造函数,不能用new
  4. 箭头函数不能使用yeild,不是一个Generator函数

var f = v => v;
// 等同于
var f = function (v) {  
  return v;
};

6.数组的扩展
  1. 扩展运算符
  2. Array.from()
  3. Array.of()
  4. 数组实例的 copyWithin()
  5. 数组实例的 find() 和 findIndex()
  6. 数组实例的 fill()
  7. 数组实例的 entries(),keys() 和 values()
  8. 数组实例的 includes()
  9. 数组实例的 flat(),flatMap()
  10. 数组的空位
  11. Array.prototype.sort() 的排序稳定性
扩展运算符

将一个数组转换为逗号分隔的参数序列
let a = [1,2,3]
...a // 1,2,3

Array.from()

将类数组转换成数组
let array = {
  '0':'2',
  '1':'4',
  length:2
}
Array.from(array); // ['a','b']
//可以传入第二个参数
Array.from(array,x=>x*x) // [4,16]

Array.of()

将一组值转换为数组
Array.of(3,5,6) //[3,5,6]
Array.of() //[]
//原生实现Array.of
function ArrayOf(){
  return [].slice.call(arguments);}

数组实例

copyWithin()

将制定位置上的成员复制到其他成员上,会覆盖原有成员
copyWithin(target,start,end) target目标元素、start开始位置、end结束位置
[1,2,3,4,5].copyWithin(0,3)用三号位及其后元素,从0号位开始覆盖 // [4,5,3,4,5]
[1,2,3,4,5].copyWithin(0,3,4)用三号位,覆盖0号位 // [4,2,3,4,5]
[1,2,3,4,5].copyWithin(0,-2,-1)用三号位,覆盖0号位 // [4,5,3,4,5] 相当于copyWithin(0,3,4)

find()、findIndex()

find() 找到符合条件的第一个元素,没有找到返回undefined
findIndex() 找到符合条件的第一个元素的下标,如果没有找到返回-1
[1,2,3,4,-5].find(v=>v<0)  //-5
[1,2,3,4,5].findIndex(v=>v>4)  //4
可以传递第二个参数,绑定回调函数的this
function f(v){
  return v>this.age
}
let person = {age:25,name:'a'}
[10,23,45,67].find(f,person);

fill()

给定一个值填充数组
['a','b','c'].fill(7)  // [7,7,7]
new Array(3).fill(7)  //[7,7,7]
['a','b','c'].fill(7,1,2) //['a',7,'c']
//如果赋值的是一个对象,则填充的是同一个对象,并且是浅拷贝
let arr = new Array(3).fill({name:'san'}) // [{name:'san'},{name:'san'},{name:'san'}]
arr[0].name = 'ben';
console.log(arr) // [{name:'ben'},{name:'ben'},{name:'ben'}]

entries()、keys()、values()

for(let [index,key] of ['a','b'].entries()){
  console.log(index,key)
}
// 0,'a'
// 1,'b'
如果不用for of,可以使用next方法
let entries = ['a','b'].entries();
entries.next().value //'a'
entries.next().index // 1

includes()

[1,2,3].includes(3) //true

flat()、flatMap()

flat() 数组扁平化,默认扁平化一层
[1,2,3,[4,5]].flat() //[1,2,3,4,5]
[1,2,3,[4,[5,6]]].flat() //[1,2,3,4,[5,6]][1,2,3,[4,[5,6]]].flat(2) //[1,2,3,4,5]
flatMap() 每个元素增加一个map方法
[1,2,3].flatMap(v=>v*2) //[2,4,6]
[1,2,3].flatMap(v=>[[x*2]]) //[[2],[4],[6]]

数据的空位
Array.prototype.sort
7.对象的扩展
  1. 属性的简洁表示法
  2. 属性名表达式
  3. 方法的 name 属性
  4. 属性的可枚举性和遍历
  5. super 关键字
  6. 对象的扩展运算符
  7. 链判断运算符
Null 判断运算符
1.简洁表示
=> 
let a = {a,methods(){}}
let a = {a:a,
methods:function(){
}
}
      2.属性名表达式
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
3.方法的name属性
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
4.对象的结构
let {a,b,...z} = {a:1,b:2,c:3,d:4}
//a 1
//b 2
//z {c:3,d:4}
注意:解构赋值必须为最后一个参数,是浅拷贝
5.链判断运算符?
let a = b?.c?.d
?. 左侧存在时,才会往下走

8.对象新增方法
  1. Object.is()
  2. Object.assign()
  3. Object.getOwnPropertyDescriptors()
  4. __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
  5. Object.keys(),Object.values(),Object.entries()
  6. Object.fromEntries()
1.Object.is 判断两个值是否值相等,解决NaN === NaN //false, +0 === -1//true的问题

Object.is('foo','foo')//true
Object.is({},{})//false
2.Object.assign  合并对象,浅拷贝

Object.assign({},{a:1})  //{a:1}
object.assign({a:1,b:2},{c:3})//{a:1,b:2,c:3}
object.assign({a:1,b:2},{a:3})//{a:3,b:2},有相同的键时,后面会覆盖前面的值
3.Object.getOwnPropertyDescriptors获取某个对象的属性描述

Object.getOwnPropertyDescriptors({a:1})
// {  a:{       
        value:1,      
        enumberable:true,
        writable:true, 
        configurable:true   
    }}
4.Object.getPrototypeOf 、Object.setPrototypeOf  获取/设置一个对象的原型

Object.getPrototypeOf(1) //Number.prototype
Object.setPrototype({},null)  //给空对象设置原型为null
5.Object.keys(),Object.values(),Object.entries()

let a = {a:1,b:2,c:3}Object.keys(a)  //['a','b','c']
Object.values(a) //[1,2,3]
Object.entries(a) //['a','b','c']  [1,2,3]
6.Object.fromEntries()和Object.entries相反

Object.fromEntries([ 
 ['foo', 'bar'],  ['baz', 42]
])
// { foo: "bar", baz: 42 }