call、apply、bind的区别

  1. call()
var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this.user); //Super苹果核
    }
}
var b = a.fn;
b.call(a);

通过在call方法,把b添加到call方法的第一个参数的环境中,简单来说,this就会指向那个对象。

call方法除了第一个参数以外还可以添加多个参数,如下:

var a = {
    user:"Super苹果核",
    fn:function(e,ee){
        console.log(this.user); //Super苹果核
        console.log(e+ee); //3
    }
}
var b = a.fn;
b.call(a,1,2);

2.apply()

var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this.user); //Super苹果核
    }
}
var b = a.fn;
b.apply(a);

同样apply也可以有多个参数,但是不同的是,第二个参数必须是一个数组,如下:

var a = {
    user:"Super苹果核",
    fn:function(e,ee){
        console.log(this.user); //Super苹果核
        console.log(e+ee); //11
    }
}
var b = a.fn;
b.apply(a,[10,1]);

或者:

var a = {
    user:"Super苹果核",
    fn:function(e,ee){
        console.log(this.user); //Super苹果核
        console.log(e+ee); //520
    }
}
var b = a.fn;
var arr = [500,20];
b.apply(a,arr);

注意如果call和apply的第一个参数写的是null,那么this指向的是window对象

var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this); //Window {external: Object, chrome: Object, document: document, a: Object, speechSynthesis: SpeechSynthesis…}
    }
}
var b = a.fn;
b.apply(null);

3.bind()
bind方法和call、apply方法有些不同,但是不管怎么说它们都可以用来改变this的指向。
先来说说它们的不同吧:

var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a);

我们发现代码没有被打印,对,这就是bind和call、apply方法的不同,实际上bind方法返回的是一个修改过后的函数。

var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
var c = b.bind(a);
console.log(c); //function() { [native code] }

那么我们现在执行一下函数c看看,能不能打印出对象a里面的user

var a = {
    user:"Super苹果核",
    fn:function(){
        console.log(this.user); //Super苹果核
    }
}
var b = a.fn;
var c = b.bind(a);
c();

ok,同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的。

var a = {
    user:"Super苹果核",
    fn:function(e,d,f){
        console.log(this.user); //Super苹果核
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

总结:call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别,根据自己的实际情况来选择使用。

文章来源:http://www.cnblogs.com/pssp/p/5215621.html

call()和apply()就是改变函数的执行上下文,也就是this值。他们两个是Function对象的方法,每个函数都能调用。他们的第一个参数就是你要指定的执行上下文,第二个用来传递参数(说第二个不准确,应该说第二部分,因为参数可以传多个),也就是传给调用call和apply方法的函数的参数。说白了,就是调用函数,但是让它在你指定的上下文下执行,这样,函数可以访问的作用域就会改变。下面看点代码:

function apply1(num1, num2){
    return sum.apply(this, [num1, num2]);
}
function call1(num1, num2){
    return sum.call(this, num1, num2);
}

这里,我们执行环境传的是this,也就是说没改变函数的执行上下文。这两段代码,只是想告诉你call和apply的区别。
call的第二部分参数要一个一个传,apply要把这些参数放到数组中。这就是他们的区别,真的就这么点区别!!!
然后,不得不说的一点:它们的第二个参数都可以传arguments。

下面来讲bind()函数,bind()是es5中的方法,他也是用来实现上下文绑定,看它的函数名就知道。bind()和call与apply不同。bind是新创建一个函数,然后把它的上下文绑定到bind()括号中的参数上,然后将它返回。
所以,bind后函数不会执行,而只是返回一个改变了上下文的函数副本,而call和apply是直接执行函数。

下面代码可以反映出这点,而且也显示了bind的用法

var button = document.getElementById("button"),
    text = document.getElementById("text");
button.onclick = function() {
    alert(this.id); // 弹出text
}.bind(text);

但由于ie6~ie8不支持该方法,所以若想在这几个浏览器中使用,我们就要模拟该方法,这也是面试常考的问题,模拟的代码如下:

if (!function() {}.bind) {
    Function.prototype.bind = function(context) {
        var self = this
            , args = Array.prototype.slice.call(arguments);

        return function() {
            return self.apply(context, args.slice(1));    
        }
    };
}

就是这段代码,纠正了我长久以来的一个误区。下面来讲一下这段代码
首先,我们判断是否存在bind方法,然后,若不存在,向Function对象的原型中添加自定义的bind方法。
这里面var self = this这段代码让我很困扰,按理说,prototype是一个对象,对象的this应该指向对象本身,也就是prototype,但真的是这样吗。看看下面的代码:

function a(){};
a.prototype.testThis = function(){console.log(a.prototype == this);};
var b = new a();
b.testThis();//false

显然,this不指向prototype,而经过测试,它也不指向a,而指向b。所以原型中的this值就明朗了。指向调用它的对象。
Array.prototype.slice.call(arguments);
接下来就是上面这段代码,它会将一个类数组形式的变量转化为真正的数组。为啥呢,其实书上并没有说slice还有这样的用法,也不知道是谁发明的。slice的用法可以顺便上网查一下,就能查到。但要更正一点,网上的介绍说slice有两个参数,第一个参数不能省略。然而我不知道是我理解的问题还是咋地,上面这段代码tmd不就是典型的没传参数吗!!!arguments是传给call的那个上下文,前面讲过,不要弄混(由于arguments自己没有slice方法,这里属于借用Array原型的slice方法)。而且经过测试,若果你不给slice传参数,那就等于传了个0给它,结果就是返回一个和原来数组一模一样的副本。
这之后的代码就很好理解,返回一个函数,该函数把传给bind的第一个参数当做执行上下文,由于args已经是一个数组,排除第一项,将之后的部分作为第二部分参数传给apply,前面讲过apply的用法。
如此,我们自己的这个bind函数的行为就同es5中的bind一样了。

文章来源:http://blog.csdn.net/u014267183/article/details/52610600

apply、call、bind比较

apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个例子:

var obj = {  
    x: 81,  
};  

var foo = {  
    getX: function() {  
        return this.x;  
    }  
}  

console.log(foo.getX.bind(obj)());  //81  
console.log(foo.getX.call(obj));    //81  
console.log(foo.getX.apply(obj));   //81 

三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。
  也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
  再总结一下:
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值