JavaScript
进制转换
可以使用toString(a),进行进制转换,a填需要转换的进制
let a = 10 |
字符串新增方法
- includes():是否找到了参数字符串。
- startsWith():参数字符串是否在原字符串的头部。
- endsWith():参数字符串是否在原字符串的尾部。
- repeat(n):将原字符串重复n次。会先将n取整,若仍为负数,则报错
Infinity;若n为字符串,则转换成数字。 - padStart():用于头部补全。
- padEnd():用于尾部补全。
- trimStart()、trimLeft():消除字符串头部的空格。
- trimEnd()、trimRight():消除尾部的空格。
- matchAll():返回一个正则表达式在当前字符串的所有匹配,返回的是一个遍历器(Iterator),需要使用for…of取出,也可以使用结解构将其转成数组
[...string.matchAll(regex)]。 - replaceAll():可以一次性替换所有匹配,
searchValue必须是全局的正则表达式。 - at():返回参数指定位置的字符。
padStart用途:
- 用于尾部补全
'1'.padStart(10, '0') // "0000000001" |
- 提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12" |
正则表达式
| 符号 | 含义 |
|---|---|
| . | 匹配任何字符 |
| * | 匹配前一个表达式零次或多次 |
| + | 匹配前一个表达式一次或多次 |
| ? | 匹配前一个表达式零次或一次 |
| ^ | 匹配输入字符串的开始位置 |
| $ | 匹配输入字符串的结束位置 |
| \d | 匹配数字字符 |
| \D | 匹配非数字字符 |
| \w | 匹配字母、数字或下划线字符 |
| \W | 匹配非字母、数字或下划线字符 |
| \s | 匹配空白字符 |
| \S | 匹配非空白字符 |
| [] | 匹配方括号中的任意一个字符 |
| () | 分组,用于限制操作符的作用范围、改变操作符的优先级、捕获匹配项等。 |
1. RegExp 构造函数
// 第一种情况 |
2. 正则表达式方法
- match()
- replace()
- search()
- split()
3. u 修饰符
用来正确处理大于\uFFFF的 Unicode 字符
/^\uD83D/u.test('\uD83D\uDC2A') // false |
4. y 修饰符
exec方法
var s = 'aaa_aa_a'; |
y修饰符和g修饰符类似,都是从上一次搜索到的位置开始匹配字符,但是y修饰符不一样,y修饰符要求在字符串的头部就匹配到数据,否则返回空。
代码分析:执行第一次匹配后,都是输出aaa,剩余字符串为_aa_a;第二次匹配,都是从第一次匹配剩余的字符串的_开始,g修饰符会搜索剩余字符串所有符合的结果,而y修饰符会从头开始匹配,如果不合适(即_与a不匹配),则直接返回null
实际上,y修饰符号隐含了头部匹配的标志^。
match方法
'a1a2a3'.match(/a\d/y) // ["a1"] |
代码分析:匹配到第一次字符a1,将匹配结果返回,进行匹配下一个字符,由于y修饰符限制,正则表达式只能从上次成功匹配的字符a之后开始匹配,也就是a后面的1开始匹配,由于头部匹配不合适,则返回null。
5. s 修饰符
点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外:一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(line terminator character)。
行终止符:
- U+000A 换行符(
\n) - U+000D 回车符(
\r) - U+2028 行分隔符(line separator)
- U+2029 段分隔符(paragraph separator)
/foo.bar/s.test('foo\nbar') // true |
6. 断言
先行断言(lookahead):x只有在y前面才匹配,必须写成/x(?=y)/
先行否定断言(negative lookahead):x只有在y前面才匹配,必须写成/x(?=y)/
/\d+(?=%)/.exec('100% of US presidents have been male') // ["100"] |
后行断言(lookbehind):x只有在y后面才匹配,必须写成/(?<=y)x/
后行否定断言(negative lookbehind):x只有在y后面才匹配,必须写成/(?<=y)x/
/\d+(?=%)/.exec('100% of US presidents have been male') // ["100"] |
7. Unicode 属性类
匹配满足条件的所有字符
const regexGreekSymbol = /\p{Script=Greek}/u; |
\p{Script=Greek}表示匹配一个希腊文字母,所以匹配π成功。
8. v 修饰符
可以向某个 Unicode 属性类添加或减少字符
// 差集运算(A 减去 B) |
// 十进制字符去除 ASCII 码的0到9 |
9. 具名组匹配
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; |
“具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名“(?<year>),然后就可以在exec方法返回结果的groups属性上引用该组名。同时,数字序号(matchObj[1])依然有效。
解构赋值和替换
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar'); |
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; |
引用
如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/; |
数字引用(\1)依然有效。
const RE_TWICE = /^(?<word>[a-z]+)!\1$/; |
10. d 修饰符
这个修饰符可以让exec()、match()的返回结果添加indices属性,在该属性上面可以拿到匹配的开始位置和结束位置。
const text = 'zabbcdef'; |
结束位置是匹配结果的下一个字符
数值
1. 数值分隔符
类似1000可以写作1,000
let budget = 1_000_000_000_000; |
数值分隔符没有指定间隔的位数,可以每三位添加一个分隔符,也可以每一位、每两位、每四位添加一个。其他进制的数值也可以使用分隔符。数值分隔符只是一种书写便利,对于 JavaScript 内部数值的存储和输出,并没有影响。
数值分隔符有几个使用注意点:
- 不能放在数值的最前面(leading)或最后面(trailing)。
- 不能两个或两个以上的分隔符连在一起。
- 小数点的前后不能有分隔符。
- 科学计数法里面,表示指数的
e或E前后不能有分隔符。 - 分隔符不能紧跟着进制的前缀
0b、0B、0o、0O、0x、0X。
下面三个将字符串转成数值的函数,不支持数值分隔符。
- Number()
- parseInt()
- parseFloat()
Number('123_456') // NaN |
2. Number
Number.isFinite()用来检查一个数值是否为有限的(finite),不是数值直接返回false。
Number.isFinite(15); // true |
Number.isNaN()用来检查一个值是否为NaN。
Number的这两个方法和直接调用这两个方法的区别:
isFinite会将非数值转为数值,在进行判断,而Number的isFinite会直接判断数值,如果不为数值,则直接返回false。
isFinite(25) // true |
Number.isInteger()用来判断一个数值是否为整数。
整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。如果参数不是数值,则直接返回false
Number.isInteger(25) // true |
如果数值超过精度会将后面位舍弃,可能会出现误判;或者一个数的绝对值小于Number.MIN_VALUE(5E-324),即最小分辨值,会自动转为0,这是也会误判。
Number.isInteger(3.0000000000000002) // true |
Number.EPSILON表示 1 与大于 1 的最小浮点数之间的差。等于 2 的 -52 次方。
Number.EPSILON === Math.pow(2, -52) |
误差范围设为 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)),即如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等。
/** |
Number.isSafeInteger()用来判断一个整数是否在这个范围之内,JavaScript 能够准确表示的整数范围在-2^53到2^53之间。
大整数计算时,只检验计算结果不行,可能会出现错误,如果a远比b大,进行计算时,a会以最大上限整数进行存储,而不是a的真实值。
Number.isSafeInteger(9007199254740993) |
3. Math
Math.trunc方法用于去除一个数的小数部分,返回整数部分,不会进行四舍五入。
Math.sign方法用来判断一个数到底是正数、负数、还是零。
- 参数为正数,返回
+1; - 参数为负数,返回
-1; - 参数为 0,返回
0; - 参数为-0,返回
-0; - 其他值,返回
NaN。
Math.cbrt()方法用于计算一个数的立方根。
Math.clz32()方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。左移运算符(<<)与Math.clz32方法直接相关。对于小数,Math.clz32方法只考虑整数部分。
Math.imul方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。主要用于大整数计算。
Math.fround方法返回一个数的32位单精度浮点数形式。
Math.hypot方法返回所有参数的平方和的平方根。
Math.hypot(3, 4); // 5 |
Math.expm1(x)返回e的x次方-1
$$
e^x-1
$$Math.log1p(x)方法返回1 + x的自然对数
$$
ln(1+x)
$$Math.log1p(x)方法返回1 + x的自然对数
$$
log_{10}(x)
$$Math.log2(x)返回以 2 为底的x的对数。
$$
log_2(x)
$$
Math.sinh(x)返回x的双曲正弦(hyperbolic sine)Math.cosh(x)返回x的双曲余弦(hyperbolic cosine)Math.tanh(x)返回x的双曲正切(hyperbolic tangent)Math.asinh(x)返回x的反双曲正弦(inverse hyperbolic sine)Math.acosh(x)返回x的反双曲余弦(inverse hyperbolic cosine)Math.atanh(x)返回x的反双曲正切(inverse hyperbolic tangent)
4. BigInt
大整数,BigInt 类型的数据必须添加后缀n。
除法运算会舍弃小数位;
BigInt不能与普通数值进行混合运算,|、+;
比较运算符可以与其他类型值混合计算;
BigInt 与字符串混合运算时,会先转为字符串,再进行运算。
函数
1. 基本用法
参数默认值不是传值的,而是每次都重新计算默认值表达式的值。
let x = 99; |
2. 与参数解构赋值结合
function foo({x, y = 5} = {}) { |
3. 参数默认位置
function foo(x = 5, y = 6) { |
undefined触发默认值,null不会
4. 函数的length属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数,rest参数也不在length中。
如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
(function (a = 0, b, c) {}).length // 0 |
5. 作用域
let x = 1; |
函数f调用时,参数y = x形成一个单独的作用域,并没有定义变量x,所以从全局变量找x。
var x = 1; |
执行y()的时候,y()和函数参数的x在同一作用域内,所以函数的参数x的值被改为2;函数体内使用var声明了一个和外部同名的变量x,并且赋值为3,这个变量只是一个局部变量,虽然和外面的全局变量同名但是本质不同,所以外部的x没有变,仍为1,所以foo最后一行代码输出的为3。
刚开始:
全局作用域:
| 变量 | 值 |
|---|---|
| x | 1 |
foo函数的参数作用域(当前作用域由于y参数没有执行,所以x参数仍为undefined):
| 变量 | 值 |
|---|---|
| x | undefined |
| y | function ( ) { x = 2; } |
执行foo()函数:
全局作用域:
| 变量 | 值 |
|---|---|
| x | 1 |
foo函数内部作用域:
| 变量 | 值 |
|---|---|
| x | 3 |
foo函数的参数作用域(此时已经执行y()函数,所以x的值从undefined变为2):
| 变量 | 值 |
|---|---|
| x | 2 |
| y | function ( ) { x = 2; } |
6. rest 参数
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 rest 参数的形式为...变量名
function add(...values) { |
arguments对象,是一个类似数组的对象,所以需要使用Array.from将其转为数组
function add(...values) { |
注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
7. 严格模式
只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
原因是:函数执行的时候,先执行函数参数,然后再执行函数体,这样不合理。
严格模式下不能用前缀0表示八进制
解决方法(把函数包在一个无参数的立即执行函数里面):
const doSomething = (function () { |
8. name 属性
函数的name属性,返回该函数的函数名。
9. 箭头函数
var f = v => v; |
如果箭头函数只有一行语句,且不需要返回值,可以采用下面的写法,就不用写大括号了。
let fn = () => void doesNotReturn(); |
注意:
- 箭头函数没有自己的
this对象,使用箭头函数的this指向上一层的作用域。 - 不可以当作构造函数,也就是说,不可以对箭头函数使用
new命令,否则会抛出一个错误。 - 不可以使用
arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。 - 不可以使用
yield命令,因此箭头函数不能用作 Generator 函数。 - 箭头函数也没有
arguments、super、new.target变量,都指向外层的变量 - 箭头函数不能使用
call()、apply()、bind()这些方法
(function() { |
部署管道机制(pipeline)的例子
const pipeline = (...funcs) => |
10. 尾调用
尾调用(Tail Call)是函数式编程的一个重要概念,指某个函数的最后一步是调用另一个函数。
以下三种情况,都不属于尾调用。
// 情况一 |
ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。
func.arguments:返回调用时函数的参数。func.caller:返回调用当前函数的那个函数。
尾递归
尾递归优化过的 Fibonacci 数列实现如下。
// 原函数 |
尾递归优化
function sum(x, y) { |
报错,提示超出调用栈的最大次数
蹦床函数(trampoline)可以将递归执行转为循环执行。
function sum(x, y) { |
这里是返回一个函数,然后执行该函数,而不是函数里面调用函数,这样就避免了递归执行,从而就消除了调用栈过大的问题。
蹦床函数并不是真正的尾递归优化,下面的实现才是。
function tco(f) { |
分析:待分析
11. 函数参数的尾逗号
ES2017 允许函数的最后一个参数有尾逗号(trailing comma)。
function clownsEverywhere( |
12. Function.prototype.toString()
返回函数一模一样的原始代码。
function /* foo comment */ foo () {} |
13. catch 命令的参数省略
使用try...catch的时候catch后面可以不接参数,但是捕获不到异常
try { |
数组
实例
eg1:直接使用Math.max()求最大值,参数为数组时可以使用...解构
// ES5 的写法 |
eg2:push()函数,将一个数组添加到另一个数组的尾部
ES5之前由于push()方法的参数不能是数组,所以只好通过apply()方法变通使用push()方法。
// ES5 的写法 |
eg3:创建时间
let date = new Date(...[2023, 6, 20, 17, 40, 59]) |
eg4:复制数组
// ES5 的写法 |
eg5:合并数组
这两种方法属于浅拷贝
const arr1 = ['a', 'b']; |
es6:与解构赋值结合
扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
// ES5 |
1. 扩展运算符
只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错。
(...[1, 2]) |
2. 替代函数的 apply() 方法
不再需要apply()方法将数组转为函数的参数
// ES5 的写法 |
3. 字符串
扩展运算符还可以将字符串转为真正的数组。
能够正确识别四个字节的 Unicode 字符。
[...'hello'] |
4. 类数组的对象
类数组的对象也可以通过扩展运算符得到数组
let arrObj = { |
脚本技巧
获取子节点
使用document.getElementsByClassName().childNodes可以获取子节点的列表
例:全选复选框
let divs = document.getElementsByClassName('board-item') |







