概述
JS中的 call,apply 和 bind 是 Function.prototype 下的方法,都是用于改变函数执行时的上下文。最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回 undefined。它们的作用都是改变当前函数 this 的指向。
Call
call 方法接收的是参数列表,简单说就是需要把实参按照形参的个数传进去
call 方法的第一个参数用于改变 this 指向,但是如果传入 null / undefined 值,this 会指向 window
'use strict' // 严格模式
var obj = {
value: '我是obj对象'
}
function fn(a, b) {
console.log(this)
console.log(a + b)
}
fn(10,20) // 普通模式下 this 是 window,在严格模式下 this 是 undefined 30
fn.call('',10,20) // 普通模式下 this 是 {''}, 在严格模式下 this 是 '' 30
fn.call(obj,10,20) // 普通模式下 this 是 obj, 在严格模式下 this 是 obj 30
fn.call(null,10,20) // 普通模式下 this 是 window,在严格模式下 this 是 null 30
fn.call(undefined,10,20) // 普通模式下 this 是 window,在严格模式下 this 是 undefined 30
call 应用场景
- 验证是否是数组
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]'
}
var obj = {
name: 'lisi'
}
var arr = [1, 2, 3, 4, 5, 6]
console.log(isArray(obj)) // false
console.log(isArray(arr)) // true
- 将伪数组转为标准数组
<body>
<div>one</div>
<div>two</div>
<div>three</div>
<script>
function change(arr){
return Array.prototype.slice.call(arr)
}
var divs = document.getElementsByTagName("div")
console.log(divs) // HTMLCollection(3) [div, div, div]
console.log(change(divs)) // [div, div, div]
</script>
</body>
apply
apply 方法的第二个参数需要传入一个实参列表,也就是数组或类数组
apply 方法的第一个参数用于改变 this 指向,但是如果传入 null / undefined 值,this 会指向 window
apply 应用场景
- 获取数组中的最大值和最小值
const arr = [1,2,3,4,5,6]
const max = Math.max.apply(null, arr)
const min = Math.min.apply(null, arr)
console.log(max) // 6
console.log(min) // 1
- 数组之间追加(拼接数组)
const arr1 = [1, 2, 3, 'name']
const arr2 = ['age', 4, 5, 6]
Array.prototype.push.apply(arr1, arr2)
console.log(arr1) // [1, 2, 3, "name", "age", 4, 5, 6]
- 封装一个简单的 log 方法
function log() {
console.log.apply(console, arguments)
}
log(123) // 123
log('name', 456) // name 456
bind
bind 方法直接改变这个函数的 this 指向并且返回一个新的函数,之后再次调用这个函数的时候 this 都是指向 bind 绑定的第一个参数。IE6、7、8不支持
bind 方法的第一个参数也是用于改变 this 指向,如果传入null / undefined,this 会指向window
bind 方法可以使函数拥有预设的初始参数。这些参数(如果有的话)作为 bind () 的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面
bind 的第二个参数传入是 参数列表
var obj = {
name: 'lisi',
age: 20
}
function Person(name, age) {
console.log(this.name, this.age)
console.log(name, age)
console.log(arguments)
}
var fn = Person.bind(obj,'zhangsan', 21)
fn(1,2,3)
// lisi 20
// zhangsan 21
// Arguments(5)["zhangsan", 21, 1, 2, 3]
bind 的第二个参数传入是 实参列表(数组)
var obj = {
name: 'lisi',
age: 20
}
function Person() {
console.log(this.name, this.age)
console.log(arguments)
}
var fn = Person.bind(obj, ['zhangsan',20])
fn(1,2,3)
// lisi 20
// Arguments(4)[Array(2), 1, 2, 3]
call 和 apply 的区别
- call 是 apply 的语法糖
- call 和 apply 都是改变 this 指向后并执行函数
- call 和 apply 的第一个参数的作用相同,都是让另外一个对象替换当前对象,改变 this 的指向
- call 的第二个参数传入的是参数列表,apply 的第二个参数传入的是实参列表,也就是数组或类数组
call 和 bind 的区别
- call 是改变 this 指向后并执行函数,bind 是返回改变 this 指向后的函数
- call 的第二个参数传入的是参数列表,bind 的第二个参数(可选)可以是参数列表,也可以是实参列表(数组)