apply,call,bind之间的相同点与区别
apply、call、bind共同点
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
apply、call、bind不同点
bind是偏函数型,返回对应函数,便于稍后调用,
apply、call则是立即调用,不同的是需要把参数按顺序传递进去,例如:func.call(this, arg1, arg2);。(非严格模式下)当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
而 apply 则是把参数放在数组里,例如:func.apply(this, [arg1, arg2])。
Call来实现改变this指向
Function.prototype.myCall = function (context){
var context = context || window;
context.fn = this;
var args = [];
for(let i = 0,len = arguments.length;i<len;i++){
args.push(i)
}
var result = context.fn()
delete context.fn
return result
}
var a = {
name:'xiaomin',
getname:function(){
console.log(this.name)
}
}
var obj= {
name:'xiaohong'
}
let c = a.getname
c.myCall(obj);
这样利用了this的隐式绑定方法,当c在调用myCall时,myCall里面的this发生隐式绑定在了c这个函数上面, 在用我们接收到的对象生成这个方法即:
context.fn = this;
来实现在obj上面调用getname方法,自然里面的this也会指向我们传入得到的obj
当然这样做存在缺陷
即当我们传入得obj里面也有fn属性时会发生一些微小的差异:一把原先的值替换,二然后再删除这个属性
var obj = {
name:'xiaohong',
fn:'exact'
}
console.log(obj)
a.getname()
let c = a.getname
c.myCall(obj);
console.log(obj)
所以一定要注意这个属性唯一且原对象没有这个属性
所以有如下改动
Function.prototype.call = function (context) {
let context = context || window;
// 合理使用symbol 生成一个独一无二的值
let fn = Symbol('fn');
context.fn = this;
let args = [];
for(let i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
let result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
类似的实现apply函数
Function.prototype.apply = function (context, args) {
let context = context || window;
context.fn = this;
let result = eval('context.fn(...args)');
delete context.fn
return result;
}