看完这篇文章,你将了解:
- 正则对象的 exec() 方法
- setTimeout 第三参数的含义
- document.write 方法会将参数转为字符串
- 事件捕获与冒泡(简要)
- for 循环和 let 循环的区别
- 几点细节
- JS 动态规划
RegExp.exec()
这是一个正则表达式对象的方法,类似于 String.match(),返回目标字符串的匹配结果,于 match 不同的是:
- match 是 String 对象的方法,而 exec 是正则对象的方法
- 正则表达式若有
g
, match 是一次返回所有结果,而 exec 是一个一个返回
比如:
此外,根据 MDN,exec 的返回值格式如下:
setTimeout 的第三参数
setTimeout 是有第三参数的。
事实上,第一参数代表回调,第二参数代表时间,而第三参数及以后的参数都会传给回调函数作为实参
比如:
function a(x, y) {
console.log(x, y) // 2 3
}
setTimeout(a, 1000, 2, 3)
document.write 方法会调用 toString()
先看一段代码
var str1=new RegExp("e")
console.log(str1.exec("hello"))
// ["e", input: "hello", index: 1, groups: undefined]
document.write(str1.exec("hello"))
// e
这里我一开始以为文档会打印 [Object Object]
,结果是 e
为什么是这样呢?因为
- document.write 的时候会将里面的参数先转成字符串
- 执行结果是数组,而数组调用 toString 方法等价于 .join(',')
- 数组的 join 方法只收集键值为序号的元素
可以在控制台验证
var str1=new RegExp("e")
console.log(str1.exec("hello").toString())
// e
var arr = ["e", "a"]
console.log(arr.toString())
// e,a
var arr = ["e"]
arr.input = "hello"
arr.index = 1
arr.groups = undefined
// ["e", input: "hello", index: 1, groups: undefined]
console.log(arr.toString())
// e
事件捕获与冒泡
浏览器对事件的处理顺序是 先捕获,后冒泡,一个事件是捕获还是冒泡,规定在 addEventListener 的第三参数
element.addEventListener(event, function, useCapture)
捕获为 true, 冒泡为 false, 默认为 false
也就是说,我们一般添加的事件视为冒泡,默认从内到外触发
window.history
- forward: 加载 URL 历史列表的当前 URL 的下一个地址( === go(1))
- back: 加载 URL 历史列表的当前 URL 的上一个地址( === go(-1))
- go: 传入一个数字参数表示加载 URL 历史列表相对于当前 URL 的第几个地址
- length:一个属性,指示当前 URL 历史列表的长度
let 循环和 var 循环的区别
先看两段代码
for(var i = 0; i < 5; i++){
requestAnimationFrame(() => console.log(i));
}
// 5 5 5 5 5
for(let i = 0; i < 5; i++){
requestAnimationFrame(() => console.log(i));
}
// 0 1 2 3 4
这两段代码涉及到两个知识点。一是 var 和 let 的区别,二是异步
先来看循环变量用 var 定义和 let 定义的区别
for(var i=0; i<10; i++) {}
i // 10
// for 语句里 var 定义的变量会成为全局变量
for(let j=0; j<10; j++) {}
j // Error
// for 语句中 let 定义的变量不会在循环外生效
据我猜测,var 版本的循环,i 被定义为全局变量,而且循环结束后等于最后一次自增后的值,等定时器跑完后再回来看,读到的 i 是全局的 i,也就是 5。
而 let 版本的循环,读取的 i 总是限定于循环作用域的,虽然都是 i,但实际是 5 个不同的变量
细节
- 1/0 的结果是 Infinity, 不是 NaN
xx in 数组
是一个判断语句,判断 xx 是否是数组中的键(序号)。- 其实更准确点 in 运算符是对象所属,用来检查左边是否为右边的键
1 && 2
的结果是 2
JS 动态规划
今天在力扣上完成了三道动态规划题。
一般来说,动态规划就两步:
- 寻找状态转移方程
- 利用状态转移方程编程计算所有状态
寻找状态转移方程就是找规律,找规律就是假设。
想知道 P(i, j) 等于多少,从头算起很难。那就先假设我知道 P(i - 1, j), P(i, j - 1), P(i - 1, j - 1) 等较小问题的答案时,会怎么计算 P(i, j)。假设未知为已知,用当成已知的未知推导更大的未知
编程计算所有状态,用数组。遍历数组求各个结点下的状态值即可。
遍历的时候注意确保顺序正确,确保每个当前遍历结点所需的已知结点已提前经过。
更多参考
最长回文串题解 (这位老哥教会我用跨度遍历数组,见下图)
动态规划三种入手思路 (还是这位老哥,教会我计算最大子序列和)
用跨度遍历数组的顺序,也就是从子串长度遍历
金句
- setTimeout 的第三参数及以后的参数会被当成回调函数的实参传入
- document.write 方法执行时会先将参数转为字符串
- 点击事件默认从内到外触发
- for(var i=0; i<10; i++) {} 循环执行后 i 会成为全局变量且等于 10
- 动态规划一般分两步:寻找状态转移方程, 计算所有状态
暂无评论