cocos2d - JS 进阶主题 call() 、apply() 和 bind() 解析

Tips : Call 和 apply 非常类似 以Call方法为例.

Call方法 :

定义:

调用一个对象的一个方法,以另一个对象替换当前对象。

说明:

Call 方法可以用来代替另一个对象调用一个方法。
Call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

JavaScript 代码 :

    var Animal = cc.Sprite.extend({
        name : null,
        ctor: function(){
            this._super();
            this.name = "Animal";
        },

        showName: function(){
            cc.log(this.name);
        },
    })

    var Cat = cc.Sprite.extend({
        name : null,
        ctor: function(){
            this._super();
            this.name = "Cat";
        },
    }) 

    var cat = new Cat();
    var animal = new Animal();

    animal.showName()             //结果为Animal
    cat.showName();               //报错

    animal.showName.call(cat);    //结果为Cat

    //通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。    
    //animal.showName.apply(cat,[]);  

call 的意思是把 animal 的方法放到cat上执行,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,所以this.name 应该是 Cat

JavaScript 代码 :

    function add(a,b)  
    {  
        alert(a+b);  
    }  
    function sub(a,b)  
    {  
        alert(a-b);  
    }  

    add.call(sub,3,1);   

这个例子中的意思就是用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4);

注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。


Call 和 Apply 的区别 :

定义一个log方法 :

    function log(msg){
        console.log(msg);
    }

log(1) // 1
log(1, 2) // 1

可以看出来 这个方法只能接受一个参数, 虽然可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 替代 call .

注意 :

这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:

function log(){
    console.log.apply(console, arguments);
}

再次尝试 :
log(1) // 1
log(1, 2) // 1 2

结果就正确了!

其实, 在 cocos2d - js 里 cc.log 的实现方式正是如此 !

这里写图片描述


bind() 方法 :

bind方法本身和 apply 、call很类似, 也同样是改变this指向的方法, 但是bind使用的地方与apply 和 call 有些不同.

注意 :

bind方法会创建一个新函数, 称作绑定函数, 当调用bind函数时, 为以第一个参数为this(通常传入的也是this), 传入bind的第二个以及以后的参数加上绑定函数运行时本身的参数, 按照顺序作为原函数的参数来调用函数.

在具体实例中, 我们通常用self、that等, 用来保存this, 例如 :

    var foo = {
        num: 1,
        eventBind: function(){
            var self = this;
            $('.someClass').on('click',function(event) {
                console.log(self.num);     //1
            });
        }
    }

————————-下文为网络原文————————-
由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $(‘.someClass’).on(‘click’,function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:

    var foo = {
        bar : 1,
        eventBind: function(){
            $('.someClass').on('click',function(event) {
                console.log(this.bar);      //1
            }.bind(this));
        }
    }

在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 被传入(调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this( foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。

例如:

    var bar = function(){
    console.log(this.x);
    }

    var foo = {
    x:3
    }

    bar(); // undefined
    var func = bar.bind(foo);
    func(); // 3

这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。

有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:

    var bar = function(){
        console.log(this.x);
    }

    var foo = {
        x:3
    }

    var sed = {
        x:4
    }

    var func = bar.bind(foo).bind(sed);
    func(); //?

    var fiv = {
        x:5
    }

    var func = bar.bind(foo).bind(sed).bind(fiv);
    func(); //?

答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。


Apply 、Call 、 Bind 比较

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


    var A = {
        name : "A",
    }

    var B = {
        name : "B",

        getName : function(){
            console.log(this.name);
        },
    }

    B.getName.bind(A)();  //A  
    B.getName.call(A);    //A
    B.getName.apply(A);   //A

三个输出的都是A,但是注意看使用 bind() 方法的,他后面多了对括号。

也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。


总结:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

你可能感兴趣的:(JavaScript,Cocos2d,-,JS,游戏开发)