以下都是在非严格模式下进行讨论
一、apply与call
function f1(x,y){
console.log("结果是:" + (x + y) + this);
}
f1(10,20); //30[object Window] 此时this指向window对象,很好理解
f1.apply(null,[10,20]); //30[object Window]
f1.call(null,10,20); //30[object Window]
apply和call方法中如果第一个参数传入的是null,那么调用该方法的函数对象中this仍默认的指向。两个作用一致,只是传参形式不同。
function f1(x,y){
console.log("结果是:" + (x + y) + this);
}
var obj = {
age: 10,
sex: "male"
}
f1.apply(obj,[10,20]); //30[object Object]
f1.call(obj,10,20); //30[object Object]
console.dir(obj); // obj中不存在f1方法
第一个参数传入对象后,可以修改this指向,此时指向传入的对象。需要注意的是apply和call只是”临时借用“obj对象,并不会将方法添加到该对象中。
二、扩展问题:apply和call到底属于谁的方法?
function f(){
console.log(this+'我被调用了');
}
f.apply();
f.call();
console.dir(f);
输出结果
首先我们知道f既是函数也是对象,上段代码中显示f能够调用apply和call方法,那么f中是否含有apply和call呢?所以我用console.dir查看了下f函数的结构:
f函数对象结构
发现事情并不简单,两个方法并不是直接存在与f函数对象中。那就往原型对象中查找,函数对象f是谁的实例对象呢?Function!
console.log(f.__proto__ == Function.prototype) //true
console.dir(Function);
Function对象
现在结果就很明了了,所有函数都是Function的实例对象,而apply和call都属于Function的原型对象(prototype)之中。
三、bind方法
function f1(x,y){
console.log("结果是:" + (x + y) + this);
}
f1.bind(); //此时函数并没有执行,这里只是单纯的复制了一份
var ff = f1.bind();
ff(10,20); //30[object Object] 此时没有传入指向对象,故保持默认
var fz = f1.bind(null,10,20);
fz(); //30[object Object] 与ff结果一样,只不过是第二种写法,参数两处都可以传入
var obj = {
age: 10,
sex: "male"
}
var fzy = f1.bind(obj,10,20);
fzy(); //30[object Object]
总结一下:
①bind方法是复制的意思,即复制一份新函数,参数可以在复制的时候传入,也可以在复制之后调用时传入
②call和apply是调用的时候改变this指向--适用于直接调用
③bind是复制该函数 的时候改变了this 的指向,适合作为参数传递
网友评论