相同点:在特定的作用域中调用函数均能改变this的指向;
不同点:call和apply除了传参方式不同其他的作用是完全相同的,call的传参方式是散列的,apply则是传一个数组,且使用call和apply后函数会立即执行,而bind则返回一个新的函数等待被调用。
在这里稍微仿写以下这三个的实现方法:
call和apply:
var name = 'window';
function show(name,age){
this.name = name;
this.age = age
console.log(this,this.name,this.age);
return this.name + this.age;
}
var obj = {
name: 'obj',
age: 18
}
show('window',18) //window 'window' 18
show.call(obj,'call',30) //obj 'call' 30
show.apply(obj,['apply',18]) //obj 'apply' 18
Function.prototype.myCall = function(target){
var args = Array.prototype.slice.call(arguments,1);
var arr = [];
for(var i = 0; i < args.length; i++){
arr.push('args['+i+']');
}
target.fn = this;
var result = eval('target.fn('+ arr.join(",") +')');
delete target.fn;
return result;
}
show.myCall(obj,'myCall',30);//obj 'myCall' 30
Function.prototype.myApply = function(target){
var args = arguments[1];
var arr = [];
for(var i = 0; i < args.length; i++){
arr.push('args['+i+']');
}
target.fn = this;
var result = eval('target.fn('+ arr +')');
delete target.fn;
return result;
}
show.myApply(obj,['myApply',18]); //obj "myApply" 18
bind:
var name = 1;
Father.prototype.lastName = 'dn';
function Father(){
}
fn.prototype = new Father();
function fn(name,age){
this.name = name;
this.age = age;
console.log(this,this.name,age,this.lastName);
}
obj = {
name:'xx'
}
fn('ll',22);
//this-->window 'll' 22 undefined
fn.call(obj,'liu',18);
//this--> obj{name:'liu',age:18} 'liu' 18 undefined
var newFn = fn.bind(obj);
newFn('zhang',19);
//this --> obj{name:'zhang',age:19} 'zhang' 19 undefined
var newFb = fn.bind(obj,'xu');
newFb(20);
//this --> obj{name:'xu',age:20} 'xu' 20 undefined
var newb = newFn.bind(window);
newb('lei',22);
//bind --> 只能进行一次改变this指向,后面无用
//this ---> obj{name:'lei',age:22} 'lei' 22 undefined
new newFn('new',5);
//this ---> fn的对象{name:'new',age:5} 'new' 5 'dn' 改变了bind的this
Function.prototype.myBind = function(target){
var target = target || window;
var args = Array.prototype.slice.call(arguments,1);
// console.log(args)
var self = this;
var temp = function(){};
var F = function(){
// console.log(this)
var arg = args.concat(Array.prototype.slice.call(arguments,0));
// console.log(arg)
return self.apply(this instanceof temp? this : target,arg);
}
temp.prototype = self.prototype;
F.prototype = new temp();
return F;
}
var fnMyBind = fn.myBind(obj,'mybind');
fnMyBind(18)
// this ---> obj{name:'mybind':age:18} 'mybind' 18 undefined;
var fnBindBind = fnMyBind.myBind(window)
fnBindBind(666);
// this ---> obj{name:'mybind':age:666} 'mybind' 666 undefined;
new fnMyBind(99);
//this --->fn的对象{name:'mybind',age:99} 'mybind' 99 'dn'