JavaScript之call、apply、bind
2023-07-20 本文已影响0人
h2coder
前言
在JavaScript中,this指向总是动态的,但也提供了手动改变this指向的方法,那就是call()、applay()和bind(),那么它们之间又有什么区别呢?
Call
语法
fn.call(this, arg1, arg2, arg3...);
示例
// 改变 this 的指向
const obj = {
name: '八戒',
say(a, b) {
console.log(a, b);
console.log(this);
}
};
const newObj = {
name: '悟空'
};
obj.say();// 输出八戒对象本身
// 通过call,改变this指向为 newObj
obj.say.call(newObj, 11, 22);// 输出悟空对象本身
总结
使用call()能改变函数的this,并且马上调用该函数,函数的参数是一个接一个传入
Apply
语法
fn.apply(this, [arg1, arg2, arg3...]);
示例
// 改变 this 的指向
const obj = {
name: '八戒',
say(a, b) {
console.log(a, b);
console.log(this);
}
};
const newObj = {
name: '悟空'
};
// apply的效果和call的效果一致,区别只是传参的方式不同
// apply()的话,参数必须放到数组中,放在第二个参数
// call()的话,参数是放在剩余参数上
obj.say.apply(newObj, [11, 22]);// 输出悟空对象本身
总结
apply()和call()一样,都能改变this指向,也是马上调用该函数,但函数的参数必须放在数组中
Bind
语法
let newFn = fn.bind(this);
newFn(arg1, arg2, arg3...);
示例
// 改变 this 的指向
const obj = {
name: '八戒',
say(a, b) {
console.log(a, b);
console.log(this);
}
};
const newObj = {
name: '悟空'
};
// bind()不会直接调用函数,而是返回一个新函数,但它的this指向已经被修改过了
const fn = obj.say.bind(newObj);
fn(11, 22);
总结
bind()也可以改变函数的this指向,但不会马上调用函数,而是返回一个新函数,函数的参数是在调用返回的新函数时,一个接一个的传入
this的取值
this的取值 不取决于函数的定义,而是取决于怎么调用的(this指向调用者)
- 全局内调用: fn() 指向window
- 对象内的方法调用:obj.fn() 指向调用对象
- 构造函数调用:new Person() 指向实例对象
- 事件处理函数中调用:指向当前触发事件的DOM元素
- 特殊调用 比如 call、apply、bind可以改变this指向,fun.call(obj) 指向 obj
应用场景
call的应用场景
- 判断变量的类型
// Object.prototype.toString.call(目标变量) 最强大,判断得最准确
// 代码太长,还要严谨地判断字符串结果,建议进行封装来使用
Object.prototype.toString.call(1);//[object Number]
Object.prototype.toString.call('hello');//[object String]
Object.prototype.toString.call(true);//[object Boolean]
Object.prototype.toString.call(null);//[object Null]
Object.prototype.toString.call(undefined);//[object Undefined]
Object.prototype.toString.call([]);//[object Array]
Object.prototype.toString.call({});//[object Object]
apply的应用场景
- 让Math.max()、Math.min()等函数,支持数组
// apply的应用场景,很像展开运算符,能把数组参数拆开成单个参数来调用
const max = Math.max.call(null, [1, 2, 3]);
// ES6展开运算符,更简洁
// const max = Map.max(...[1, 2, 3]);
console.log(`数组的最大值:${max}`);
bind的应用场景
// bind的应用场景,改变定时器或延时器的this指向
const button = document.querySelector('button');
button.addEventListener('click', function (e) {
const fn = function () {
console.log(this);
};
// 改变延时器回调函数的this
setTimeout(fn.bind(this), 1000);
});