JavaScript 为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this
的指向问题,常用的有 bind()
、call()
、apply()
三种方法。
1. call
1. call用法
call()
方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this
指向
fun.call(thisArg, arg1, arg2, ...);
thisArg
:在fun
函数运行时指定的this
值arg1
,arg2
:传递的其他参数- 返回值就是函数的返回值,因为它就是调用函数
- 因此当我们想改变
this
指向,同时想调用这个函数的时候,可以使用call()
,比如继承
var o = {
name: 'andy',
};
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2); // 此时的this指向的是window 运行结果为3
fn.call(o, 1, 2); // 此时的this指向的是对象o,参数使用逗号隔开,运行结果为3
fn.call(1, 2); // this->1, a=2, b=undefined
另外,在严格模式
下和非严格模式
下,this
有所区别:
// 非严格模式
fn.call(); // this -> window
fn.call(null); // this -> window
fn.call(undefined); // this -> window
// 严格模式
fn.call(); // this -> undefined
fn.call(null); // this -> null
fn.call(undefined); // this -> undefined
2. call用例
(1)判断数据类型
使用Object.prototype.toString
可以判断数据类型。
const a = [1, 2, 3];
const b = {
name: 'jack',
age: 18,
};
const c = 10;
const typeA = Object.prototype.toString.call(a); // [object Array]
const typeB = Object.prototype.toString.call(b); // [object Object]
const typeC = Object.prototype.toString.call(c); // [object Number]
(2)类数组转数组
使用Array.prototype.slice
可以将类数组转化为数组。
const arrayLike = {
0: 'Jack',
1: 'Tim',
2: 'Jone',
3: 'Randy',
length: 4,
};
// [ 'Jack', 'Tim', 'Jone', 'Randy' ]
const arr = Array.prototype.slice.call(arrayLike);
2. apply
1. apply用法
apply()
方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的this
指向。
apply()
和call()
方法的作用是一模一样的,都是用来改变方法的this
关键字并且把方法执行,而且在严格模式
下和非严格模式
下,对于第一个参数是null
/undefined
这种情况的规律也是一样的。
fun.apply(thisArg, [argsArray]);
thisArg
:在fun
函数运行时指定的this
值arg1
,arg2
:传递的其他参数,写成数组
形式传递- 返回值就是函数的返回值,因为它就是调用函数
apply()
主要跟数组有关系,比如使用Math.max()
求数组的最大值
var o = {
name: 'andy',
};
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(); // 此时的this指向的是window 运行结果为3
fn.apply(o, [1, 2]); //此时的this指向的是对象o,参数使用数组传递 运行结果为3
2. apply用例
借用Math.max
方法,将数组作为参数传递进去,求最大值或最小值。
const nums = [1, 2, 3, 4, 5];
const max = Math.max.apply(null, nums); // 5
const min = Math.min.apply(null, nums); // 1
3. bind
1. bind用法
bind()
方法不会调用函数。但是能改变函数内部this
指向。
在严格模式
下和非严格模式
下,对于第一个参数是null
/undefined
这种情况的规律与call()
相同。
fun.bind(thisArg, arg1, arg2, ...);
thisArg
:在fun
函数运行时指定的this
值arg1
,arg2
:传递的其他参数- 返回由指定的
this
值和初始化参数改造的原函数拷贝 - 因此当我们只是想改变
this
指向,并且不想调用这个函数的时候,可以使用bind()
var o = {
name: 'andy',
};
function fn(a, b) {
console.log(this);
console.log(a + b);
}
// 这里不会输出任何值,因为bind并不调用函数
fn.bind(o, 1, 2);
// 此处的f是bind返回的新函数
var f = fn.bind(o, 1, 2);
// 调用新函数 this指向的是对象o,参数使用逗号隔开
f();
4. 三者的异同
-
共同点:都可以改变
this
指向 -
不同点:
call()
和apply()
会调用函数,并且改变函数内部this
指向.call()
和apply()
传递的参数不一样,call()
传递参数使用逗号隔开,apply()
使用数组传递bind()
不会调用函数,可以改变函数内部this
指向
-
应用场景
call()
经常做继承apply()
经常跟数组有关系,比如借助于数学对象实现数组最大值最小值bind()
不调用函数,但是还想改变this
指向,比如改变定时器内部的this
指向
call() | apply() | bind() | |
---|---|---|---|
相同点 | 改变函数this 指向 | 改变函数this 指向 | 改变函数this 指向 |
是否调用函数 | 是 | 是 | 否 |
传递参数 | 逗号, 隔开 | 数组形式[] | 逗号, 隔开 |
应用场景 | 继承 | 与数组有关 | 不想调用函数 |
📘📘欢迎在我的博客上访问:
https://lzxjack.top/