JS函数

定义一个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1. 具名函数
function 函数名(形式参数1, 形式参数2){
语句
return 返回值
}

// 2. 匿名函数(即具名函数去掉函数名,也叫函数表达式)
let a = function(x,y) {
return x+y;
}

// 3. 箭头函数
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;
}) // 直接返回对象会报错,需要加圆括号


// 4. 用构造函数
let f5 = new Function('x','y','return x+y') // 基本没人用,所有函数都是Function构造出来的,包括Object、Array

函数自身与函数调用

1
2
let fn = () => console.log('hi');
fn // 不会有任何结果,因为fn没有调用
1
2
let fn = () => console.log('hi');
fn() // 打印出hi,有圆括号()才是调用
1
2
3
4
5
let fn = () => console.log('hi')
let fn2 = fn
fn2()
// fn保存了匿名函数的地址,这个地址被复制给了fn2,fn2()调用了匿名函数
// fn和fn2()都是匿名函数的引用而已,真正的函数不是fn也不是fn2

JS函数执行时机

函数的调用时机不同,会得到不同结果

1
2
3
4
5
6
let a = 1
function fn() {
console.log(a)
}

// 不知道会打印出什么,因为没有调用函数
1
2
3
4
5
6
7
let a = 1
function fn(){
console.log(a)
}
fn()

// 打印出1
1
2
3
4
5
6
7
8
let a = 1
function fn(){
console.log(a)
}
a = 2
fn()

// 打印出2
1
2
3
4
5
6
7
8
let a = 1
function fn(){
console.log(a)
}
fn()
a = 2

// 打印出1
1
2
3
4
5
6
7
8
9
10
let a = 1
function fn(){
setTimeout(()=>{
console.log(a)
},0)
}
fn()
a = 2

// 打印出2

异步函数

1
2
3
4
5
6
7
8
9
let i = 0
for(i = 0; i < 6; i++){
setTimeout(()=>{
console.log(i)
},0)
}

// 会打印出6个6,而不是0,1,2,3,4,5
// setTimeout会等当前的for循环执行完,再去执行console.log(i),而for循环执行完后,i=6,所以会打印出6个6

如何让上面的代码打印出0,1,2,3,4,5

  1. for、let配合使用,let会单独创建一个作用域,每次循环会多创建一个i,相当于有6个i

    1
    2
    3
    4
    5
    for(let i = 0; i < 6; i++){
    setTimeout(()=>{
    console.log(i)
    },0)
    }
  2. 在for循环内部声明一个新的变量来存储i的值

    1
    2
    3
    4
    5
    6
    7
    let i
    for(i = 0; i < 6; i++){
    let x = i
    setTimeout(()=>{
    console.log(x)
    },0)
    }
  3. 立即执行函数,把当前for循环过程中的i传递进去,构建块级作用域

    1
    2
    3
    4
    5
    6
    7
    for (var i = 0; i < 6; i++){
    (function(i){
    setTimeout(()=>{
    console.log(i)
    }, 0)
    })(i)
    }
  4. 利用setTimeout函数的第三个参数,会作为回调函数的第一个参数传入

    1
    2
    3
    for(i = 0; i < 6; i++){
    setTimeout(console.log(i), 1000, i)
    }
  5. 利用try…catch…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for(var i = 0; i < 6; i++){ 
    try{
    throw i;
    }catch(i){
    setTimeout(() => {
    console.log(i)
    }, 0)
    }
    }
  6. 使用递归配合setTimeout()

    1
    2
    3
    4
    5
    function fn(i){
    return i < 6 ? setTimeout(()=>{console.log(i);fn(++i),0}) : i
    }

    fn(0)
  7. 利用promise

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    for (var i = 0; i < 6; i++) {
    timeoutPromise(i);
    }
    function timeoutPromise(i) {
    return new Promise((resolve) => {
    setTimeout(() => {
    console.log(i);
    resolve(true);
    }, 0)
    })
    }
0%