apply,call和bind的使用及区别
1、用途
1)apply,call和bind都是 用来改变this的指向
2)apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行
2、this指向问题
this的指向有以下四种情况:
1)如果函数中的this没有调用对象,则this指向window(严格模式下,this为undefined)
2)如果函数中this被不包含子对象的对象调用,则this指向调用它的对象
3)如果函数中this被包含多级对象的对象调用,则this指向调用它的上一级对象
4)如果我们调用了对象,并将其赋值给某个变量,然后在需要的时候再去调用执行它,则此时this也是指向的window对象,如:
var a = obj.myFunc;
a();
var name="zhang"; var age=18; var obj={ name:"liu", myAge:this.age, myFun:function(){ console.log(this); // this指向obj console.log(this.name+";"+this.age) } } obj.myAge // 18 obj.myFun()
上图是我们很常用的一个对象属性的获取和方法的调用,在我们获取obj.myAge属性时,这里的this实际是window对象,所以我们去找window.age,找到的是全局参数age=18
在调用myFun()方法时,本着谁调用this就指向谁的基本原则,此时this指向的是obj对象,所以我们输出的this.name为liu,this.age为undefined
上面的例子如果不太好理解的话,我们看下面这个更直观的例子:
var name="zhangsan"; function showName(){ console.log(this); console.log(this.name); } showName();
我们在这里直接定义了一个方法,并且调用了它,上面说了,谁调用函数,函数里面的this就指向谁,但是我们这里直接调用了showName(),并没有明确说明是谁调用了它啊,其实这里我们可以理解为window.showName(),即this实际上是指向的window。
3、apply和call
1)先来看看call是如何实现的:
Function.prototype.call=function(context){
// 这里的this指向demo函数
console.log(this); context=context?Object(context):window; context.fn=this; var args=[];
// 参数从1开始循环因为第一个参数是context for(var i=1;i<arguments.length;i++){ args.push("arguments["+i+"]"); }
// 这里执行context.fn() 即上面的demo(),所以this指向了context,但是因为我们没有传递context,所以this指向了window var r = eval("context.fn("+args+")") delete context.fn; return r; } var name="test" function demo(){ console.log(this) console.lot(this.name) } demo.call();
1) 当我们传递了context时,context为我们传递的对象;否则为window对象。
2) 谁调用,this指向谁,我们通过demo.call 调用了call方法,所以这里的this指向的时demo函数
3)将传递的参数放进args中
4)通过eval函数执行我们的context.fn,即上面的demo函数
5)demo函数中,this指向的时call方法中的context,这里时window对象
6)this.name即window.name
2)call其实是apply的一个语法糖,他们的作用都是用于改变上下文的指向,区别在于,call接受多个参数,而apply接受的是一个数组
var db={
name:"dema"
}
var obj={ name:"obj", myFunc:function(from,to){ console.log(this); console.log(this.name+"来自:"+from,+"去往:"+to); } }
obj.myFunc.call(null,'北京','上海') // this 指向window,this.name=undefined,from=北京,to=上海
obj.myFunc.call(db,'北京','上海'); // this指向db,this.name='dema',from=北京,to=上海
obj.myFunc.apply(db,['北京','上海']); // this指向db,this.name='dema',from=北京,to=上海
上面例子中,我们分别调用了call和apply,并传入了参数null,db和地名,从上面的call的实现中,可以看到,我们接受的第一个参数是上下文context,用于改变this的指向。
所以上面第一行,传入的context为null,则this指向window,第二行和第三行,都传人了context为db,所以this此时是指向db的,即this.name=db.name
4、bind
bind也是用于改变上下文的指向,它和call一样,接受多个参数。
bind和apply,call的区别在于,bind返回一个方法,用于后面调用,apply和call会直接执行
function print(a,b,c){ console.log(a,b,c) } var fn = print.bind(null,'D') fn('A','B','C') // D,A,B