「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
前言
众所周知call apply bind都可以改变函数调用的this指向,从而改变执行上下文的。今天我们就来看看三者有什么区别、如何使用以及实现原理?
call
我们可以通过call来改变this指向,call方法挂载在Function的原型链中的Function.prototype.call()。在MDN中是这样介绍的call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
基本使用
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this); // person
console.log(this.name, age, sex); // 小飞仔 25 男
}
sayHi.call(person, 25, '男');
代码大致执行过程是这样的。首先寻找call方法,让sayHi方法中的this变为第一个参数值person,最后再把sayHi这个函数执行。
我们在试一下thisArg传null会返回Window对象
function sayHi() {
console.log(this); // Window
}
sayHi.call(null);
我们在试一下thisArg传undefined会返回Window对象
function sayHi() {
console.log(this); // Window
}
sayHi.call(undefined);
我们在试一下thisArg传0会返回Nunber{0}对象
function sayHi() {
console.log(this); // `Nunber{0}
}
sayHi.call(0);
源码实现
Function.prototype.myCall = function (thisArg, ...args) {
if (typeof thisArg === 'object') {
thisArg = thisArg || window
} else {
thisArg = new Object(thisArg)
}
thisArg.fn = this
let result = thisArg.fn(...args)
thisArg.fn = null
return result;
}
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this); // person
console.log(this.name, age, sex); // 小飞仔 25 男
}
sayHi.myCall(person, 25, '男');
apply
我们可以通过apply来改变this指向,apply方法挂载在Function的原型链中的Function.prototype.apply()。在MDN中是这样介绍的apply()方法调用一个具有给定this值的函数,以及以一个数组的形式提供的参数。
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
sayHi.apply(person, [25, '男']); // 小飞仔 25 男
源码实现
Function.prototype.myApply = function (thisArg, ...args) {
if (typeof thisArg === 'object') {
thisArg = thisArg || window
} else {
thisArg = new Object(thisArg)
}
thisArg.fn = this
thisArg.fn(...args)
delete thisArg[fn]
}
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
sayHi.myApply(person, [25, '男']); // 小飞仔 25 男
bind
我们可以通过bind改变this指向,apply方法挂载在Function的原型链中的Function.prototype.apply()。在MDN中是这样介绍的MDN 是这样描述的bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
sayHi.bind(person, 25, '男')(); // 小飞仔 25 男
源码实现
Function.prototype.myBind = function (thisArg,innerArgs) {
var _this = this
return function (...finnalyArgs) {
return _this.call(thisArg,...innerArgs,...finnalyArgs)
}
}
let person = {
name: '小飞仔'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
sayHi.apply(person, [25, '男']); // 小飞仔 25 男
总结
call、apply是一个数组。大致相同区别在于call参数不同一个是对象一个是数组。bind则返回一个新的对象。