西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网
当前位置: 主页 > 开发教程 > JavaScript教程 >

Javascript中call的使用

时间:2016-01-23 09:49来源:未知 作者:好模板 点击:
Javascript中call的使用自己感觉蛮纠结的,根据文档很好理解,其实很难确定你是否真正的理解。 call 方法 应用于:Function 对象 调用一个对象的一个方法,以另一个对象替换当前对象。

Javascript中call的使用自己感觉蛮纠结的,根据文档很好理解,其实很难确定你是否真正的理解。 call 方法 应用于:Function 对象 调用一个对象的一个方法,以另一个对象替换当前对象。 call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 参数:thisObj 可选项。将被用作当前对象的对象。 arg1, arg2, , argN 可选项。将被传递方法参数序列。 说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

  1. 最基本的理解自定义一个类,该类有一个方法showTxt,用来显示当前对象的name值。创建一个对象,并且该对象的name值等于test1。使用call方法,使新创建的对象obj添加Class1类的showTxt方法,即把Class1类中的this.showTxt中的this指定成obj,这样obj就有了showTxt方法。弹出”test1″。这个例子很容易理解。

    function Class1(){
        this.showTxt = function(){alert(this.name)}
    }
    var obj = new Object();
    obj.name="test1"
    Class1.call(obj);
    obj.showTxt();//test1
    alert(obj.showTxt);//function(){alert(this.name)}  
  2. 再看一个稍微深入的理解创建Class1的实例,让这个实例调用showTxt方法返回这个实例的name值,因为这个实现没有name值所以返回undefine。

    function Class1(){
        this.showTxt = function(){alert(this.name)}
    }
    var class1 = new Class1();
    class1.showTxt();//undefined
    alert(class1.showTxt);//function(){alert(this.name)}
  3. 下面就给 Class1 添加个 name 值,这时 class1 再调用 showTxt 方法,会返回 class1 ,这是因为给类添加了 name 值,所以实例的 name 也由undefine 变成了 class1 .

    function Class1(){
        this.name = 'class1';//添加name值
        this.showTxt = function(){alert(this.name)}
    }
    var class1 = new Class1();
    class1.showTxt();//class1
    alert(class1.showTxt);//function(){alert(this.name)}
  4. Class1.call(obj) 这个操作把 Class1 中的 this.name , this.showTxt里的 this 替换成了 obj ,所以就变成了 obj.name='class1' ,所以obj.showTxt 在执行时返回 class1 。

    function Class1(){
        this.name = 'class1';//添加name值
        this.showTxt = function(){alert(this.name)}
    }
    function Class2(){
        this.name = 'class2';
    }
    var class2 = new Class2();
    Class1.call(class2);
    alert(class2.showTxt);//function(){alert(this.name)}
    class2.showTxt();//class1
  5. 如果在 Class1.call(obj); 之后再添加 obj.name = 'test1' ,最后结果会输入 test1 ,原因显而易见。

    function Class1(){
        this.name = 'class1';//添加name值
        this.showTxt = function(){alert(this.name)}
    }
    function Class2(){
        this.name = 'class2';
    }
    var class2 = new Class2();
    Class1.call(class2);
    class2.name = 'test1';//重定义obj.name值
    alert(class2.showTxt);//function(){alert(this.name)}
    class2.showTxt();//test1

    上面的例子 call 的都是一个对象的实例,接下来的案例把对象的实例直接换成函数,看看执行结果会发生哪些变化

  6. 把 call 方法的第一参数由实例换成函数看看会怎么样

    Class2 是一个 function 对象的引用,在执行 Class1.call(Class2) 时this.showTxt 里的 this 被替换成了 Class2 。这样 Class2 就有了showTxt 方法, Class2.showTxt() 执行时会返回 Class2.name 的值,因为Class2 并未定义 name 值,所以会返回 undefined 。

    Class2 函数里的 this.name 是由 Class2 创建实例的 name 值,并不是Class2.name ,这两个值有时会让我迷糊。

       function Class1(){
       this.showTxt = function(){alert(this.name)}
       }
       function Class2(){
       this.name = 'class2';
       }
       Class1.call(Class2);
       alert(Class2.showTxt);//function(){alert(this.name)}
       Class2.showTxt();//undefined
  7. 接着看下面的例子

    class1.showTxt.call(class2); 之所以会返回class2是因为 function(){alert(this.name)} 这里的 this 被 call 指定成了 class2 ,变成了alert(class2.name) ,所以会返回 class2 。

    alert(class2.showTxt) 返回 undefined ,说明并未定义class2.showTxt 方法。

    function Class1(){
        this.showTxt = function(){alert(this.name)}
    }
    function Class2(){
        this.name = 'class2';
    }
    var class1 = new Class1();
    var class2 = new Class2();
    class1.showTxt.call(class2);//class2
    alert(class2.showTxt);//undefined

    因为并为给 class2 添加 showTxt 方法,所以提示该错误。如果在这个调用之前添加 Class1.call(class2); 这个调用就OK了Class1.call(class2);class2.showTxt();//class1

  8. 这个例子都会返回 undefined

    function Class1(){
        this.showTxt = function(){alert(this.name)}
    }
    function Class2(){
        this.name = 'class2';
    }
    var class1 = new Class1();
    class1.showTxt.call(Class2);//undefined
    alert(Class2.showTxt);//undefined
  9. 在使用call时如果调用函数里没有 this 会怎么样

    function add(a,b){
        alert(a+b);
    }
    function sub(a,b){
        alert(a-b);
    }
    add.call(sub,3,1);//4

    结果返回4, add.call(sub,3,1) 在执行过程中, sub 做为 add 函数中this 的替代品出现,但是因为 add 里没有用到 this ,所以 sub 函数直接忽略,所以结果是4。

    所以实际执行如下:返回4。

    function add(a,b){
        alert(a+b);
    }
    add(3,1);//4
  10. 不错,接下来再理解一个怪异的形式

    function f1(){
        alert(1);
    }
    function f2(){
        alert(2)
    }
    var f3 = f1.call;
    f1.call(f2);//1
    f3.call(f2);//2

    f1.call(f2); 比较好理解,如果不理解看上边的case,但如何理解f3.call(f2) 会返回2呢,为了方便理解进行一下等效变化为f1.call.call(f2) ,这时会发现实际上是 f1.call 方法 call 调用了 f2 ,那 f1 怎么又会有 call 方法呢? call , apply 都属于Function.prototype 的一个方法,它是 JavaScript 引擎内在实现的,因为属于Function.prototype ,所以每个 Function 对象实例,也就是每个方法都有call , apply 属性。

    在理解 f1.call.call(f2) 时我们首先要知道 call 方法到底是如何执行的,这样才能 f1.call.call(f2) 如何执行。

    引用JK写的一个用apply实现call的方法:

    function jsCall(oThis){//这里的jsCall就是Call
        var argsNew = [];
        for(var i=1;i<arguments.length;i++){
            argsNew.push(arguments[i]);
        }
        return this.apply(oThis,argsNew);
    }
    Function.prototype.jsCall = jsCall;

    或简写成

    function jsCall(oThis){//这里的jsCall就是Call
        var argsNew = [].slice.call(arguments,1)    
        return this.apply(oThis,argsNew);
    }
    Function.prototype.jsCall = jsCall;

    这样就得到了一个和 call 一样功能的 jsCall , 接下来构建两个函数 f1 ,f2

    function f1(a){
        alert([this,a,'f1']);
    }
    f1(11);//[object Window],11,f1
    function f2(a){
        alert([this,a,'f2']);
    }
    f2(22);//[object Window],22,f2

    用 jsCall 把 f1 中的 this 替换成 f2

    function f1(a){
        alert([this,a,'f1']);
    }
    function f2(a){
        alert([this,a,'f2']);
    }
    f1.jsCall(f2,11);//function f2(a){alert([this, a, "f2"]);},11,f1

    执行结果发现 [object Window] 被替换成 f2 函数

    function jsCall(oThis){//这里的jsCall就是Call
        var argsNew = [].slice.call(arguments,1)    
        return this.apply(oThis,argsNew);
    }
    Function.prototype.jsCall = jsCall;
    function f1(a){
        alert([this,a,'f1']);
    }
    function f2(a){
        alert([this,a,'f2']);
    }
    f1.jsCall.jsCall(f2,11);//11,,f2

    在执行 f1.jsCall.jsCall(f2,11); 时返回 11,,f2 ,为什么会返回这个结果,重点来了:)

    f1.jsCall 方法:

    alert(f1.jsCall);
    //返回
    //function jsCall(oThis) {
    //    var argsNew = [].slice.call(arguments, 1);
    //    return this.apply(oThis, argsNew);
    //}

    所以 f1.jsCall.jsCall 可以替换成 jsCall.jsCall 看一下执行结果

    function jsCall(oThis){//这里的jsCall就是Call
        var argsNew = [].slice.call(arguments,1)    
        return this.apply(oThis,argsNew);
    }
    Function.prototype.jsCall = jsCall;
    function f1(a){
        alert([this,a,'f1']);
    }
    function f2(a){
        alert([this,a,'f2']);
    }
    jsCall.jsCall(f2,11);//11,,f2

    接着分析

    jsCall 在执行的过程中, return this.apply(oThis,argsNew); 里的this 被替换成了

    f2 , 11 做为参数传给了 (oThis,argsNew) ,变成了 f2.apply(11);

    function jsCall(oThis){//这里的jsCall就是Call
        var argsNew = [].slice.call(arguments,1)    
        return this.apply(oThis,argsNew);
    }
    Function.prototype.jsCall = jsCall;
    function f1(a){
        alert([this,a,'f1']);
    }
    function f2(a){
        alert([this,a,'f2']);
    }
    f2.apply(11);//11,,f2

    返回结果跟 f1.jsCall.jsCall(f2,11) 一样。

    回过头来看

    function f1(){
        alert(1);
    }
    function f2(){
        alert(2)
    }
    var f3 = f1.call;
    f1.call(f2);//1
    f3.call(f2);//2

    这样就不难理解 f1.call.call(f2) 实现时, f1.call 执行过程中 call 中的 this 被 f2 替换成了

    f2.call(); 因为 f2 里没有 this 的引用所以执行结果是2.

    f2.call()//2 

    需要十分注意的是 f1.call 是方法, f1 是函数对象,这两者在 call 时是有区别的。


(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容