函数的定义
具名函数
function 函数名(形式参数1,形式参数2){
语句
return 返回值
}
匿名函数
- 去掉函数名的具名函数就是匿名函数
let a = function(x,y){return x+y}
- 函数表达式
注意:如果有等于号的,只能作用于右边,也就是如果要使用函数,只能用a。相反地,如果是function直接定义,那就全局可用。
箭头函数
let f1 = x => x*x
let f2 = (x,y) => x+y //圆括号不能省略
let f3 = (x,y) => {return x+y }//花括号不能省
let f4 = (x,y) => ({name:x , age:y })
直接返回对象会出错,需要加括号,不然就变成标签了。
构造函数
let f = new Function('x','y','return x+y')
- 基本没人使用,但是可以让你知道函数是谁构造的。
- 所有函数都是Function构造(including Object、Array 、Function)
函数的要素
- 调用时机
- 作用域
- 闭包
- 形式参数
- 返回值
- 调用栈
- 函数提升
- arguments(除了箭头函数)
- this(除了箭头函数)
JS函数的执行时机
//为什么如下代码会打印 6 个 6
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
JS 函数的执行时机与其在代码中的位置有关,常见的执行时机包括函数声明、函数表达式、立即执行函数、事件回调等。
在上述代码中,由于使用了 setTimeout 函数,导致回调函数中的 console.log(i) 不会立即执行,而是会被放入一个任务队列中,等待主线程空闲后才会被执行。而在 for 循环执行过程中,变量 i 的值一直在不断地被更新,因此在回调函数被执行时,i 的值已经被更新为 6,导致打印出 6 个 6。
为了让上述代码打印 0、1、2、3、4、5,可以使用闭包的方式来保存当前的 i 值,代码如下:
for(let i = 0; i < 6; i++){
(function(i){
setTimeout(() => { console.log(i) }, 0)
})(i)
}
还有个更简洁的办法,就是直接在for里面let i = 0就行。
除了使用 for(let i = 0; i < 6; i++) 的方式,还有一种可以使用 Array.from 和 Array.prototype.map 方法来实现,代码如下:
jsCopy code
// 打印 0、1、2、3、4、5
Array.from({length: 6}).map((_, i) => {
setTimeout(() => {
console.log(i)
}, 0)
})
这种方法使用了 Array.from 方法创建一个包含 6 个 undefined 元素的数组,然后使用 Array.prototype.map 方法来对数组进行遍历,对于每个元素使用一个回调函数来设置对应的定时器。由于使用了箭头函数,因此可以访问到外部的 i 变量,从而保证每个回调函数中的 i 值都是独立的。