call、apply、bind的用法

303 阅读3分钟

call

函数的调用方式:

  1. 直接调用functionName()
  2. 使用 call 调用。functionName.call()

每一个人都会更喜欢第一种这种更简单的方式,然而,第2种才是 JavaScript 中函数的真正调用方式。
call是函数的原型Function.prototype上的方法,每一个函数都拥有。
在JS引擎中,调用一个函数的真正方式是调用函数的call方法。

函数的call方法: 语法:

fun.call(thisArg, arg1, arg2, ...)

call 调用一个函数,给该函数一个指定的 this 值 thisArg 和指定的参数 arg1, arg2, ...
call、apply 指定的参数会在 arguments 中顺序排列在原函数的参数后面。

使用 call 调用一个函数:

var obj = {
    name: 'Sam',
    age: 22,
}

function fn(){
    console.log(this)
}

fn.call(obj)    // 对象 obj {name: 'Sam',age: 22}
fn()            // 对象 window

使用 call 调用函数与直接调用函数的区别:

  • 直接调用函数是JS的一个语法糖,引擎依然会调用call方法。只是,在调用call方法时,由于没有手动指定 this 值,JS引擎会自动隐式传入一个 this 值。
  • 使用call调用函数,必须手动指定 this 的值。手动传入的 this 必须是个对象,若传入的不是对象,JS引擎会自动转换成相应类型对象。这时,函数之中的 this 就是这个手动指定的对象。
  • 需要注意的是,在非严格模式下,当使用call调用函数时,若传入的 this 是 null 或 undefined,会默认指向 window 对象。

call()的应用

  1. 将伪数组转为真正的数组
var arr = Array.prototype.slice.call(fakeArray)

Array.prototype.slice.call({0: 'a',1: 'b',length: 2})
Array.prototype.slice.call(document.querySelectorAll('div'))  // querySelectorAll 通过遍历获得元素,静态对象。添加新的元素,length不会增加
Array.prototype.slice.call(arguments)
  1. 实现对象继承
var constructor = function(name,age){
    this.name = name
    this.age = age
}
var obj = {}
constructor.call(obj,'sam',18)
console.log(obj)        // {name: sam, age: 18}

apply

apply()的用法与call()基本一致,apply()使用时接受的参数是一个数组,而不是像call()那样的参数列表。其他方面,两者并无不同。

apply()的应用

  1. 将伪数组转为真正的数组 使用方法与call()一样。
    需要注意的是,无论call()还是apply(),被转化的伪数组都必须具有length属性和对应的数字键
  2. 找出数组中的最大值
var array = [1,2,3,4,5,6,7,8,9]
Math.max.apply(undefined, array)
  1. 将数组中的空元素转换为 undefined
Array.apply(null,[1,,2])  // [1,undefined,2]

bind

bind()给函数的 this 绑定一个指定的对象,返回一个一样的新函数。bind() 不仅能绑定 this 的指向,还能绑定原函数的参数。就是说,bind()的第二个参数之后的参数是会覆盖原函数的参数。

bind比call方法和apply方法更进一步的是,除了绑定this以外,还可以绑定原函数的参数。– JavaScript标准参考教程

var obj = {
    count: 1,
    add: function(){
        this.count += 1
    }
}

var count = 20

// 对象调用方法,this指向对象
obj.count     // 1
obj.add()     
obj.count    // 2

// 函数表达式调用方法,this 指向 window
var f = obj.add
f()
count        // 21

// bind 手动指定 bind
var fn = obj.add.bind(obj)
fn()      
obj.count     // 3
count         // 21

简写原生方法

var log = console.log.call(console)
// var log = console.log.bind(console)
// Fuction.prototype.call绑定 this 为 Array.prototype.slice
var slice = Function.prototype.call.bind(Array.prototype.slice);
// slice() === Array.prototype.slice.call()