1. let、const、var的区别const和let基本一致,有一点不同,const定义的值不能改变,这里说的改变是不能改变const定义的变量的指向,内容是可以改变的
- let不能重复定义
- let没有变量提升
- let有暂时性死区(声明变量前,不可用)
- let有块级作用域
- 不会挂载在window上
const a = {}; a.b = 1;
- var可以重复定义
- var存在变量提升
- var只有全局作用域、函数作用域
- 会挂载在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.值交换
- 变量值交换
- 函数可以返回多个值
- 函数参数有所对应
- 方便提取json数据
- 函数传参加默认值
- 模块引入方法
2.函数返回多个值
let a = 1; let b = 2; [a,b] = [b,a] console.log(a,b) // 2 1
3.传参可以不按顺序
function a(){ return { b:1, c:2} } let {b,c} = a()console.log(b,c) // 1 2
4.提取jsonshuju
function b({c,d}){ console.log(c,d) } b({d:3,c:2}) //2 3
5.函数传参加默认值
let jsonData = { a:1, b:2, c:1}; let {a,b,c} = jsonData;
6.模块引入方法
function c({a=1,b=2} = {}){ console.log(a+b); } c() //3 c(1,4)//5
let {a,b} = reuire('./xx')
3.字符串的新增方法:String.fromCodePoint 将unicode转换成对应的字符,优化了es5中的fromCharCode不能转换大于0xFFFF的字符
- String.fromCodePoint()
- String.raw()
- 实例方法:codePointAt()
- 实例方法:normalize()
- 实例方法:includes(), startsWith(), endsWith()
- 实例方法:repeat()
- 实例方法:padStart(),padEnd()
- 实例方法:trimStart(),trimEnd()
- 实例方法:matchAll()
String.codePointAt与String.fromCOdePoint相反,将字符转换为unicode码,可以判断一个字符由两个字节还是四个字节组成String.fromCodePoint(a) //61
String.raw 模板字符串中斜杠都被转义:
String.codePointAt('')
实例方法:
String.raw`hi\n${1+2}` // 实际:hi\\n3,返回:hi\n3
String.startsWith、String.endsWith, String.includesrepeat
let str = 'hello'; str.startsWith('h') //true str.endsWidth('o') //true str.includes('l') //true
padStart、padEnd
'hello'.repeat(2) //hellohello 'hello'.repeat(2.8) //hellohello 向下取整 注意:不支持infinity、负数,-0.9-1之间返回0
trimStart、trimEnd
'a'.padStart(2,'0') //0a '2'.padEnd(5,'ab') //ab222
let a = ' 2 '; a.trim() //'2' a.trimStart() //'2 ' a.trimEnd() //' 2'
4.数字扩展:二进制、八进制的表示
- 二进制和八进制表示法
- Number.isFinite(), Number.isNaN()
- Number.parseInt(), Number.parseFloat()
- Number.isInteger()
- Number.EPSILON
- 安全整数和 Number.isSafeInteger()
- Math 对象的扩展
- 指数运算符
- BigInt 数据类型
Number.isFinite,Number.isNaN判断数据类型是否有限、是否为NaN二进制:0b/0B 八进制:0o/0O
Number.parseInt、Number.parseFloat将parseInt、parseFloat移植到Number上
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.isInteger 判断是否为整数,注意Number.isInteger(5E-325)自动转成0,要求高精度则不要用Number.isInteger
Math新增方法
Math.trunc( ) 取整 正数向下取整floor,负数向上取整ceil,非数字类型先转换成数字,如果转换不了返回NaNMath.sign 判断是正数、负数、0,非数字类型先转换成数字,如果转换不了返回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)
非数字转换:x = +x
Math.sign(-5) //-1 Math.sign(9) //1 Math.sign('-6') //-1 Math.sign('')//0 Math.sign(NaN)//NaN
5.函数
默认参数//存在问题,如果没有传参数,或者参数的值为空时会改变原有的值
//es5 函数不能设置默认参数 function aa(x,y){ y = y || 1 console.log(x,y) } aa(1) //1,1 aa(2,'') //2,1
//当传的参数严格等于undefined时,才会使用默认的值
//es6 function aa(x,y='1'){ console.log(x,y) } aa(1) // 1,1 aa(1,'') //1
//参数不能重名,参数与函数内部变量不能重名//参数默认值是惰性的,使用时才会计算
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,也不计入restname属性
function aa(x,...args){ console.log(args) } aa(1,2,3) //[2,3]
箭头函数
function aa(){} //aa.name => aa
- 箭头函数没有this,里面的this指向函数定义时对象
- 箭头函数没有arguments
- 箭头函数不能当构造函数,不能用new
- 箭头函数不能使用yeild,不是一个Generator函数
var f = v => v; // 等同于 var f = function (v) { return v; };
6.数组的扩展
扩展运算符
将一个数组转换为逗号分隔的参数序列
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()
find()、findIndex()将制定位置上的成员复制到其他成员上,会覆盖原有成员 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() 找到符合条件的第一个元素,没有找到返回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.对象的扩展
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 判断两个值是否值相等,解决NaN === NaN //false, +0 === -1//true的问题
- Object.is()
- Object.assign()
- Object.getOwnPropertyDescriptors()
- __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
- Object.keys(),Object.values(),Object.entries()
- Object.fromEntries()
2.Object.assign 合并对象,浅拷贝
Object.is('foo','foo')//true Object.is({},{})//false
3.Object.getOwnPropertyDescriptors获取某个对象的属性描述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},有相同的键时,后面会覆盖前面的值
4.Object.getPrototypeOf 、Object.setPrototypeOf 获取/设置一个对象的原型
Object.getOwnPropertyDescriptors({a:1}) // { a:{ value:1, enumberable:true, writable:true, configurable:true }}
5.Object.keys(),Object.values(),Object.entries()Object.getPrototypeOf(1) //Number.prototype Object.setPrototype({},null) //给空对象设置原型为null
6.Object.fromEntries()和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]
Object.fromEntries([ ['foo', 'bar'], ['baz', 42] ]) // { foo: "bar", baz: 42 }