call和apply的区别
在前端日常工作中,this的指向是一个飘忽不定但是又要掌握的知识。
在ECMAscript3中,给Fucntion.protptype定义了call和apply方法,用来改变this的指向,都接收两个参数,第一个参数都为函数体内this对象的指向,call是从第二个参数开始,每个参数给以此传入,如Fucntion.protptype.call(obj,a,b,c),apply的第二个参数为一个数组或者类数组,apply会将数组或类数组元素作为参数传递给被调用的函数,如Fucntion.protptype.apply(obj,[a,b,c])。
call和apply的用途
1.改变this指向
在开发中,this指向不经意就改变,不符合我们的预期,比如:
document.getElementById('mydiv').onclick = function () {
console.log(this.id) //输出mydiv
var fun = function () {
console.log(this.id) //输出undefined,不符合我们的预期
}
fun()
}
我们可以用call或者apply来来改变函数内的this,让其指向mydiv:
document.getElementById('mydiv').onclick = function () {
console.log(this.id) //输出mydiv
var fun = function () {
console.log(this.id) //输出mydiv1
}
fun.call(this)
}
2.借用其他对象的方法要
比如我们要找数组的最大值,想要调用Math.max(),但是此方法需要逐个输入参数,我们就可以call或者apply来实现借用:
Math.max.apply(null,[1,2,5,8,2]) //输出8
在函数中,我们会经常使用函数参数列表arguments,他是一个类数组,但是我们经常会想把他按照数组使用,我们也可以call或者apply来实现借用:
function arguToArr () {
1.
[].push.call(arguments,4,5)
console.log(arguments) // [1,2,3,4,5]
2.
let arr = [].slice.call(arguments)
console.log(arr) // [1,2,3]
}
arguToArr(1,2,3)
所以当我我们想把arguments转为数组时,可以借用Array.prototype.slice方法,当我们想截取arguments第一个参数,可以借用Array.prototype.shift方法等等...
3.实现bind,现在实现了Fucntion.protptype.bind(obj,a,b,c),但是我们也可以自己简单模拟一下:
Function.prototype.myBInd = function (obj) {
let self = this
return function () {
return self.apply(obj,arguments)
}
}
let obj = {name:'zs'}
let func = function () {
console.log(this.name) //输出zs
}.myBInd(obj)
func()
实际上bind要复杂一点:
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
// 当通过new方法调用时,this就是fNOP的一个实例
return fToBind.apply(this instanceof fNOP
? this
: oThis || this,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
bind和call、apply的区别是bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行