「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
call与apply 都是函数的方法,这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。(就是常说的改变this指向)
ECMAScript 5 出于同样的目的定义了一个新方法:bind()。bind()方法会创建一个新的函数实例, 其 this 值会被绑定到传给 bind()的对象
apply
apply()放接收两个参数,一个是函数内this的值,一个是参数数组(可以是arguments 对象,也可以是数组实例)
使用方式
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2){
console.log(co1 + '-' + co2)
console.log(this)
console.log(this.color)
}
readColor();
readColor.apply();
readColor.apply(obj, ['yellow', 'green']);
调用的结果👇🏻
上面代码,第一次调用,没有使用apply, 其this指向它调用时所处的上下文,也就是window;
第二次调用使用apply()方法,但是没有指定上下文对象,默认还是window;
第三次让其this指向obj。
ps:严格模式下,函数如果没有指定上下文对象,this值会变为undefined
"use strict";
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2){
console.log(this)
}
readColor()
readColor.apply();
实现一个apply
Function.prototype.bapply = function (ctx, args){
ctx = ctx ? Object(ctx) : window; //this指向传进来的ctx对象或window
ctx.fn = this; // 相当于给obj添加一个属性fn,fn = readColor
let result = args ? ctx.fn(...args) : ctx.fn(); // 处理参数数组
delete ctx.fn;
return result;
}
//测试
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2){
console.log(this.color)
console.log(co1 + '-' + co2)
}
readColor.bapply(obj, ['green', 'yellow']);//blue; green-yellow
call
call()方法同apply()的作用一样,区别就是传参形式不一样。
call()方法同样接收两个参数,第一个参数是相同的,都是this值;第二参数是函数接收的参数,函数接收的参数是被一个个传入call()方法里的,相当于把传给apply的参数打散一个个罗列出来传给call。
使用方式
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2){
console.log(co1 + '-' + co2)
console.log(this)
console.log(this.color)
}
readColor();
readColor.call(obj, 'yellow', 'green');
实现一个call
与apply的实现类似,区别在于参数的处理
Function.prototype.bcall = function (ctx){
ctx = ctx ? Object(ctx) : window; //this指向传进来的ctx对象或window
ctx.fn = this; // 相当于给obj添加一个属性fn,fn = readColor
let args = Array.prototype.slice.call(arguments, 1); // 取传入的参数,从第二个到最后所有
const result = ctx.fn(...args)
delete ctx.fn
return result
}
// 测试
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2){
console.log(this.color)
console.log(co1 + '-' + co2)
}
readColor.bcall(obj, 'yellow', 'green');// blue; yellow-green
bind
bind()
方法创建一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
- 返回一个原函数的拷贝,并拥有指定的
this
值和初始参数 - bind的第一个参数,就是这个新的函数实例运行时的this
- 其余参数,当函数被调用时,被预置入绑定函数的参数列表中的参数,也就是说剩下的一序列参数将会在传递的实参前传入作为它的参数
使用方式
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2,co3){
console.log(co1 + '-' + co2 + '-' + co3)
console.log(this)
console.log(this.color)
}
let bco = readColor.bind(obj, 'yellow', 'green');
bco('ppp')
实现一个bind
- bind 返回的是一个函数
- 能够接受多个参数,也能够接受柯里化形式的传参
- bind 绑定 this 只会生效一次
- 获取到调用bind() 返回值后,若当作构造函数调用的话,bind() 传入的上下文失效
Function.prototype.bBind = function (ctx){
if (typeof(this) !== 'function') { // 调用bind的是否是函数
throw new TypeError('The bound object needs to be a function');
}
let self = this;
let args = Array.prototype.slice.call(arguments, 1); // bind时传的参数
let fNOP = function() {};
let fBound = function() {
let runArgs = Array.prototype.slice.call(arguments); // 调用函数是传的参数
return self.apply(this instanceof fNOP ? this : ctx, [...args,...runArgs]);
}
if (this.prototype) {
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
}
// 测试
var color = 'red';
var obj = {
color: 'blue'
};
function readColor(co1,co2,co3){
console.log(this.color)
console.log(co1 + '-' + co2 + '-' + co3)
}
let bco = readColor.bind(obj, 'yellow', 'green');
bco('white'); // blue; yellow-green-white
小结
- call,apply和bind,主要都是用来改变函数内部this指向的
- call与apply区别在于它们接收的第二个参数(给被调用函数使用的参数列表),给apply的参数是数组或arguments对象,而给call的参数是一个一个列出来的。
- call与apply选择哪个,取决于用哪个给被调用的函数传参方便。
- call与apply直接调用函数;bind返回一个新的函数实例,不会直接调
- 严格模式下,函数如果没有指定上下文对象,this值会变为undefined