call和apply

7/8/2021 Javascript

# 二者用途

更改 this 的指向。 🌰:

var name = 'april'
var boyfriend = {
    name: 'bran',
}
function getName() {
    console.log(this.name)
}
getName() // april,返回的是全局环境下的name变量
// 如果想要获取变量boyfriend的name,可以怎么获取呢
getName.apply(boyfriend)
getName.call(boyfriend)
1
2
3
4
5
6
7
8
9
10
11

# call 的模拟实现

通过上例我们可以发现:

  • call 改变了 this 的指向,指向到 boyfriend
  • getName 函数执行了

call 方法其他特点:

  • call 方法还能给定参数执行函数
var name = 'april'
var boyfriend = {
    name: 'bran',
}
function getName(age, height) {
    console.log(this.name)
    console.log(age)
    console.log(height)
}
getName.call(boyfriend, 24, 178)
// bran
// 24
// 178
getName.apply(boyfriend, [24, 178])
// bran
// 24
// 178
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • this 参数可以传 null,当为 null 时,视为 window
var name = 'april'

function bar() {
    console.log(this.name)
}

bar.call(null) // april
1
2
3
4
5
6
7
  • 函数可以有返回值
var person = {
    name: 'april',
}

function bar(height, age) {
    return {
        name: this.name,
        height,
        age,
    }
}

console.log(bar.call(person, 160, 24))
// Object {
//    name: 'april',
//    height: 160,
//    age: 24
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

自定义实现

Function.prototype.myCall = function(context) {
    context = context || window
    context.fn = this
    let args = []
    for (let i = 1; i < arguments.length; i++) {
        args.push(`arguments[${i}]`)
    }
    // eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
    let result = eval(`context.fn(${args})`)
    delete context.fn
    return result
}
1
2
3
4
5
6
7
8
9
10
11
12

# call 和 apply 的区别

调用参数的不同:

  • call 的参数
  1. 调用 call 的对象,必须是个函数
  2. call 的第一个参数,是一个对象。Function 的调用者,将会指向这个对象,如果不传,默认为全局对象 window
  3. 第二个参数开始,可以接收任意个参数,每个参数会映射到响应位置的 Function 的参数上。
function func(a, b, c) {}

func.call(obj, 1, 2, 3)
// func 接收到的参数实际上是 1,2,3

func.call(obj, [1, 2, 3])
// func 接收到的参数实际上是 [1,2,3],undefined,undefined
1
2
3
4
5
6
7
  • apply 的参数
  1. 调用 call 的对象,必须是个函数
  2. 只接收两个参数, 第一个参数,是一个对象。Function 的调用者,将会指向这个对象,如果不传,默认为全局对象 window
  3. 第二个参数,必须是数组或者类数组,它们会被转换成类数组,传入 Function 中,并且会被映射到 Function 对应的参数上。这也是 call 和 apply 之间,很重要的一个区别。
func.apply(obj, [1, 2, 3])
// func 接收到的参数实际上是 1,2,3

// 类数组
func.apply(obj, {
    0: 1,
    1: 2,
    2: 3,
    length: 3,
})
// func 接收到的参数实际上是 1,2,3
1
2
3
4
5
6
7
8
9
10
11

# apply 的模拟实现

Function.prototype.myApply = function(context, arr) {
    context = context || window
    context.fn = this
    let result
    if (!arr) {
        result = context.fn()
    } else {
        let args = []
        for (let i = 0; i < arr.length; i++) {
            args.push(`arr[${i}]`)
        }
        result = eval(`context.fn(${args})`)
    }
    delete context.dn
    return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# apply 的一些使用

获取数组中最大的一项

let array = [3, 1, 15, 12]
let max = Math.max.apply(null, array) // max就是15
1
2

获取数组中最小的一项

let array = [3, 1, 15, 12]
let min = Math.min.apply(null, array) // min就是1
1
2
上次更新: 11/10/2021, 10:26:52 AM