编程技术文章分享与教程

网站首页 > 技术文章 正文

详解 javascript 中的 call / apply / bind

hmc789 2024-11-16 20:56:50 技术文章 2 ℃

前言

javascriptcall / apply / bind 这三个方法是日常工作中比较实用的改变函数 this 指向的方法,很方便,但由于涉及到对 this 的理解,同时也是很容易出错的方法,也是面试官喜欢问的考题之一,今天就和大家一起好好聊一聊这三个方法

call / apply / bind 的区别

我们先简单的过一下他们之间的异同点,有个简单概念之后再详细分析

共同点

他们的功能一致,都是用来改变函数this 指向

// 语法
函数.call(thisArg, arg1, arg2, ...)  
函数.apply(thisArg, [argsArray])
函数.bind(thisArg, [argsArray])  

不同点

  • call / apply 可以立即执行;bind 不会立即执行,而是返回一个函数,可以在需要的时候再执行
  • 参数不同:apply 第二个参数是数组;call 和 bind 有多个参数需要用逗号隔开挨个写

简单应用场景

  • 改写 this 指向,让目标对象使用一些方法
const person = {
    name: '江',
    say: function () {
        console.log(this.name)
    }
}

person.say()  // 江

const obj = {
    name: '李'
}

person.say.call(obj)    // 李
person.say.apply(obj)   // 李
person.say.bind(obj)()  // 李
  • 借用方法
const numbers = [5, 458 , 120 , -215 ]; 
const maxInNumbers = Math.max.apply(Math, numbers),   //458
      maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法

手写 call

Function.prototype.myCall = function (thisArg, ...argsArray) {
    // 判断 thisArg 是否 null / undefine
    if (thisArg === null || thisArg === undefined) {
        thisArg = window
    }

    console.log(this) // 这里的 this 是调用的函数
    thisArg.fn = this
    thisArg.fn(...argsArray)
}

手写 apply

Function.prototype.myApply = function (thisArg, argsArray) {
    // 判断 thisArg 是否 null / undefine
    if (thisArg === null || thisArg === undefined) {
        thisArg = window
    }

    console.log(this) // 这里的 this 是调用的函数
    thisArg.fn = this
    thisArg.fn(...argsArray)
}

手写 bind

Function.prototype.myBind = function (thisArg, argsArray) {
    // 判断 thisArg 是否 null / undefine
    if (thisArg === null || thisArg === undefined) {
        thisArg = window
    }

    console.log(this) // 这里的 this 是调用的函数
    thisArg.fn = this
    return function () {
        thisArg.fn(...argsArray)
    }
}

使用一下我们手写的三个方法,看是否满足我们的要求

const person = {
    name: '江',
    say: function (word) {
        console.log(this.name + ":" + word)
    }
}

person.say('你好')  // 江:你好

const obj = {
    name: '李'
}

person.say.myCall(obj, 'hello')     // 李:hello
person.say.myApply(obj, ['hello'])   // 李:hello
person.say.myBind(obj, ['hello'])()   // 李:hello

可以看到可以按期望输出结果了~

总结

对于改写 this 指向的实现,关键点是要理解:

  • 我们自定义的方法,必须是挂载在 Function 这个个构造函数上的,这是一个大前提,因为只有这样,我们在任意方法上使用 . 才能找到我们的方法属性(其实就是原型链
  • 还有就是对当前函数里 this 的理解,这个场景可以简单理解为 this 是谁调用就指向谁,那么
  • 函数.myCall() 就很清晰了,是函数调用了 myCall,所以 myCall 方法里的 this 指向的就是函数
  • 理解了以上两点,就只要把 this(想执行的方法) 挂到我们的目标对象thisArg上面就可以了
标签列表
最新留言