Login
芋圆社区 > 编程 > JavaScript > call,apply,bind

call,apply,bind

191
0
2022-08-01
2022-10-13
Hey、小怪兽


call()和apply()


  • • 先看一个栗子:
  • var name = '小怪兽社区'
    var web = {
        name: '芋圆社区',
    }
    function getWeb() {
        console.log(this.name)
    }
    getWeb() // '小怪兽社区',全局对象 window里name变量
    
    // 可以通过call和apply更改this的指向,获取web对象下的name
    getWeb.call(web)   // '芋圆社区'
    getWeb.apply(web)  // '芋圆社区'
  • • 从上可以看出call()和apply()可以改变this的指向,从全局变量的name改成了对象web的name
  • • 它们的区别在于传递参数:
  • var name = '小怪兽社区'
    var web = {
        name: '芋圆社区',
    }
    function getWeb(num1, num2) {
        console.log(this.name)
        console.log(num1)
        console.log(num2)
    }
    getWeb(1, 3)                    // '小怪兽社区'  1 3
    getWeb.call(null, 1, 3)         // '小怪兽社区'  1 3
    getWeb.call(web, 1, 3)          // '芋圆社区'    1 3
    getWeb.apply(null, [1, 3])      // '小怪兽社区'  1 3
    getWeb.apply(web, [1, 3])       // '芋圆社区'    1 3
  • • 从上面代码可以看出:
  • • call():
  • - 调用call()的必须是个函数,getWeb()是个函数
  • - call()的第一个参数是个对象,web就是个对象,如果不传对象就传null,默认选择全局对象window
  • - call()从第二个参数开始,接受的是一个参数列表,会映射到函数的每一个参数上
  • // 指向全局变量window
    getWeb.call(null)
    
    // 接收到的参数是1, 2, 3
    getWeb.call(obj, 1, 2, 3)
  • • apply():
  • - 调用apply()的必须是个函数,getWeb()是个函数
  • - 和call不同的是apply()只接收两个参数,第一个参数是个对象,web就是个对象,如果不传对象就传null,默认选择全局对象window
  • - 第二个参数,必须是数组或者类数组,它们会被转换成类数组,会映射到函数的每一个参数上
  • // 指向全局变量window
    getWeb.apply(null)
    
    // 只接受到了参数1, 2
    getWeb.apply(obj, [1, 2], 3)
    
    // 类数组,接受到的参数实际上是 1,2,3
    func.apply(obj, {
        0: 1,
        1: 2,
        2: 3,
        length: 3,
    })
  • • apply()还可以用来取最大值最小值
  • // Math.max取最大值
    Math.max(14, 3, 77);
    // ES5 的写法
    Math.max.apply(null, [14, 3, 77])
    // ES6 的写法
    Math.max(...[14, 3, 77])
  • • 自定义实现call():
  • 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
    }
  • • 自定义实现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
    }

bind()


  • • bind()函数和call(),apply()都是改变this的指向问题
  • • 不同的是call(),apply()是临时指定this,而bind()则是返回绑定了指定this的新函数,也就是创建了一个函数,不管怎么调用这个函数,都有着相同的this
  • let obj = {
        name: '小白',
    }
    function getName() {
        console.log(this.name)
    }
    // bind返回了一个函数
    let bindFn = getName.bind(obj)
    bindFn() // '小白'
  • • 传递参数:
  • let obj = {
        name: '芋圆社区',
    }
    function getValue(num1, num2) {
        console.log(this.name)
        console.log(num1)
        console.log(num2)
    }
    let bindFn = getValue.bind(obj, 1)
    
    bindFn(5) // '芋圆社区' 1 5
  • • 自定义实现bind()函数:
  • Function.prototype.myBind = function(context) {
        let self = this
        // 获取myBind函数从第2个参数之后的参数(包含第二个参数)
        let args = Array.prototype.slice.call(arguments, 1)
        let result_f = function() {
            // 此时的arguments是指的myBind函数返回的函数传入的参数
            let bindArgs = Array.prototype.slice.call(arguments)
            // 当作为构造函数时,this指向实例
            // 当作为普通函数时,this指向window,将绑定函数的this指向context
            return self.apply(this instanceof result_f ? this : context, args.concat(bindArgs))
        }
        // 修改返回函数的prototype为绑定函数的prototype
        // 下面三行的实现等同于 result_f.prototype = Object.create(this.prototype)
        let temp_f = function() {}
        temp_f.prototype = this.prototype
        result_f.prototype = new temp_f()
        return result_f
    }
  • • PS:自定义实现的都是从一个博客里记来的,忘记哪个博客了,到时候找到的话再标注

上一篇:对象转为字符串

下一篇:获取数组中对象的某一属性值

Comment

Message Board

编程导航

Array 基础方法

Array 进阶方法 - ES6

一些常用的方法【持续更新】

AES加密 CBC模式

滚动条滚动到底部的判断

console.log展开值不一样

JSON解析与序列化

|| 运算符的坑

对象转为字符串

call,apply,bind

获取数组中对象的某一属性值

jQuery合并ajax请求

批量命名全局变量

forEach方法

round,ceil,floor

Copyright © 2020 芋圆社区

Powered by 浙ICP备2020039309号-1

此页面不支持夜间模式!

已进入夜间模式!

已进入普通模式!

搜索框不允许为空

签到成功!经验+5!芋圆币+2!

签到失败!今日已签到!

需要登录社区账号才可以进入!

复制成功
寄,页面未加载完成或页面无锚点