01-let和const
01-共同特点
01-块级作用域
02-没有声明提升
03-不允许重复声明
02-const特有特点
01-声明不可变常量
02-不可变只针对简单的常量,复合常量只是表示指向的地址值不会变,但是内部的属性无法控制不变(const声明的对象和数组可以在后续进行相应的修改)
02-变量的解构
01-数组解构(按照顺序)
1 | let [a, b, c] = [1, 2, 3]; |
02-对象解构(按照属性名)
1 | let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; |
03-默认值
1 | let [a, b, c = 3] = [1, 2]; |
可以用于解构嵌套变量(如套娃json对象)
04-函数参数的结构赋值
按照传入参数的类型自行解构,解构失败使用默认值
05-圆括号慎用
等用到回来查
03-字符串扩展
01-for…of…遍历字符串内的每一个字符
02-unicode支持
03-模板语法
1 | `/*模板内容*/` |
可能会涉及<%%>转换问题,可以提前使用正则表达式解决
04-字符串新增方法
01-String.fromCodePoint()
正确返回Unicode码点对应的字符
02-String.raw()
生成一个把单斜杠变成双斜杠的字符换,常用语模板语法
03-codePointAt()
获得字符串某个下表字符的码点
04-normalize()
字符合成相关
05-includes(), startsWith() ,endsWith()
includes()是否包含, 第二个参数表示从第n个到结束
startsWith()是否开始于头部, 第二个参数表示从第n个到结束
endsWith()是否结束于尾部,第二个参数表示从开头到第n个,不包含
06-repeat()
返回调用该方法的字符串重复n次之后的字符串
07-padStart(),padEnd()
第一个参数表示规定的字符串长度
第二个参数表示用什么来补全
1 | 'x'.padStart(5, 'ab') // 'ababx' |
08-trimStart(),trimEnd()
消除字符串前后的空格
09-matchAll()
返回一个正则表达式在当前字符串的所有匹配
05-正则扩展
跳过
06-数值扩展
01-二进制和八进制表示法
使用0b或者0B表示二进制前缀
使用0o或者0O表示八进制前缀
02-Number.isFinite(), Number.isNaN()
检测是否有限,是否为NaN
03-Number.parseInt(), Number.parseFloat()
04-Number.isInteger()
判断是否整数
对精度要求高不要使用
05-Number.EPSILON()
用于提供一个js能够识别的最小精度数字
用于解决类似0.1+0.2!==0.3的问题
06-安全整数和 Number.isSafeInteger()
判断是否安全整数
安全整数:整数范围在-2^53
到2^53
之间(不含两个端点)的数
07-Math对象扩展
01-Math.trunc()
去除小数部分,如4.5=》4,-4.5=》-4
02-Math.sign()
判断是正数负数还是零,返回值为+1,-1,0,NaN
03-Math.cbrt()
计算立方根
04-Math.clz32()
转换为32位无符号整数
05-Math.imul()
返回两个有符号32位整数相乘的结果
相对于a*b,优点在于溢出的时候可以正确返回低位的数值
06-Math.fround()
将64位双精度浮点数转换为32位单精度浮点数
07-Math.hypot()
返回所有参数的平方和的平方根
08-对数方法(略)
09-双曲函数方法(略)
08-指数运算符
1 | 2**3=8 |
09-BigInt数据类型
没有位数限制,不会像普通数值一样丢失精度,但是只能保存整数
表示方法
1 | a = 123456789123456n |
07-函数扩展
01-函数参数默认值
01-基本用法
1 | function log(x, y = 'World') { |
02-可以与解构赋值语法一起使用
详情看上方解构赋值语法
03-有默认值的参数应该放后面
04-length问题
函数的length函数会返回该函数的参数个数,使用默认值会使计数粗线问题,返回0
05-作用域
参数使用默认值时,参数会自己形成一个作用域,先在当前作用域内找变量,再找外部变量
06-应用
可用于参数不得省略,用到再查
02-rest参数
01-用法
用于收集多余的参数
1 | function add(...values) { |
这个写法可以收集任意数量的参数,并进行数据运算
与arguments的区别,arguments是一个类似于数组的对象,但不是数组,想要使用数组的方法需要进行Array.prototype.slice.call进行转换才能使用数组方法
02-rest参数只能是最后一个参数
03-影响严格模式
使用默认值、解构赋值、或者扩展运算符,函数内部不能显式设置严格模式,否则报错
03-箭头函数
01-简单使用
1 | var f = v => v; |
02-多个参数
1 | var sum = (num1, num2) => { return num1 + num2; } |
03-如果返回的参数是对象
1 | let getTempItem = id => ({ id: id, name: "Temp" }); |
04-注意点
- this的指向问题,是指向定义时所在的对象,而不是使用时所在的对象
- 不可以当做构造函数
- 不可以使用arguments对象
- 不可以使用yield命令(这个命令没见过不知道做啥的,以后补充)
05-优点
可以用来封装回调函数,这样this只会指向创建他的对象,因此在外部调用这个方法的时候,不会因为this指向document而导致程序出错
这个优点同时也是缺点
当this需要动态变化和定义对象方法的时候,使用箭头函数会固化this指向,导致无法正确执行函数
04-尾调用优化
01-尾调用实例
1 | function f(x){ |
最后一步调用另外一个函数,就是尾调用,只有像上面格式才是,其他无论长得多像都不是尾调用
02-尾调用的作用
在函数内调用另外一个函数的时候,需要保存父函数的作用域,存入到调用栈中,如果嵌套层数过多的话,会导致调用栈过于庞大,占用过多的内存。
所以使用尾调用,因为已经没有别的可以执行了,所以系统可以放心的把外层的调用帧释放掉,只生成内层函数的调用帧。
多使用尾调用,每次调用函数的调用帧就只有一层,可以大大节省内存空间
05-尾递归优化
01-尾递归
最后一步调用自身
02-尾递归的作用
当运行一些需要递归多次的算法的时候,容易发生栈溢出,使用尾递归可以把上层调用栈释放掉,阻止了栈溢出。
08- 数组扩展
01-扩展运算符
1 | console.log(...[1, 2, 3]) |
会将数组拆分为逗号相隔的参数序列
01-数组复制
正常我们复制数组只是声明一个新的变量名,并让他指向旧数组的地址,使用旧变量名依然会影响新变量名。
使用扩展运算符可以使用类似于解构的语法来进行深拷贝。
1 | const a1 = [1, 2]; |
02-数组赋值
注意事项:用于数组赋值的时候,扩展运算符只能放在最后一步
03-拆分字符串
1 | [...'hello'] |
10-对象新增方法
03-Object.getOwnPropertyDescriptors()
01-主要作用
返回一个对象中所有的属性组合形成的对象,key为属性,value为该属性的描述对象,包括get&set方法,writeable:是否可读写,configurable:能否修改访问器属性,enumerable:是否可以使用for in循环出来。
补充重新理解的点:
01-call()和apply()
主要作用都是改变this的指向
1 | A.call(B,arg1,arg2,arg3) |
以上都是使用A的方法,只不过this这个时候指向B
可以理解为B使用了A的方法
02-get&set方法
类内部自带的方法,重写之后,涉及到属性的修改或者获取的操作时,会执行方法的逻辑
1 | class Num { |
有点难理解的点:
箭头函数,this的指向问题