zoukankan      html  css  js  c++  java
  • JavaScript的oop中的apply,call

    先明确一点,以下部分涉及到function对象和object对象.

    当有一个方法或对象,想给另一个方法使用,可以使用以下的方法,按照这个原理实现JS的继承(可以实现多个父类继承,很多语言都做不到,JS强吧.)

    阅读前需要理解的:

    JS中 没有new 的对象在对象里的this是不存在的

    例如:

    function a(){

      this.b="hi";

      this.c=function(){alert('hi');}

    }

    alert(a.b);//out undefined

    try{

    a.c();

    }catch(e){

      alert(e->getmessage());//有输出

    }

    var a =new a();

    alert(a.b);//out hi

    a.c();//out hi

    如何添加JS的静态属性或方法呢,答案如下

    a.b="hi";

    a.c=function(){alert("hi");}

    在对象里的this只有在new实例的时候才有用,因为this表示对象本身,而不是function本身

    相对于静态的,对对象添加属性或方法也可以在类的外面进行:prototype关键字

    以下两个相同:

    function t(){
        
    this.b = function(){
             alert(
    "hi");
        }
    }
    function c(){
         
    this.b="good";
    }
    c.prototype.b
    =function(){
        alert(
    "hi");
    }

    看明白上面的在看下面的,免得理解错误~

    call方法的官方解释为:
    调用一个对象的一个方法,以另一个对象替换当前对象。
    call([thisObj[,arg1[, arg2[,   [,.argN]]]]])
    参数
    thisObj
    可选项。将被用作当前对象的对象。
    arg1, arg2, , argN
    可选项。将被传递方法参数序列。
    说明
    call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
    如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
    ====================================================

    apply方法的官方解释为:
    应用某一对象的一个方法,用另一个对象替换当前对象。
    apply([thisObj[,argArray]])
    参数
    thisObj
    可选项。将被用作当前对象的对象。
    argArray
    可选项。将被传递给该函数的参数数组。
    说明
    如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
    如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。


    从上面官方的介绍可以看出,两者实现的功能是完全一样的,只是参数传递方式不一样,call是将各个参数以“,”隔开,而apply是将所有参数组成一个数组进行传递。

    简单的说就是把obj1的方法放到obj2上使用,后面的argument1..这些做为参数传入

    如果还不给力,看下例子:

     function f(){
        alert(this.a);
     }
     
    function b(){
      this.a
    ="hi";
        f.call(this);
     }
     
    new b();//alert hi

    同理想把一个对象里的方法用到令一个对象可以如下:

    function f(){
        this.b
    =function(){
         alert(this.a);
        }
       }
       
    function b(){
        this.a
    ="hi";
       }
       var t
    =new b();
       var n
    =new f();
       n.b.call(t);//alert hi

     如用apply一样的效果

    两个区别自己做测试~不解析鸟~

    有个要注意的

    代码
     function f(){
                    var a
    ="go";
                    this.d
    =function(){
                alert(go);//undefined
                        alert(a);//alert go
                        alert(this.a);
                    }
                }
                
    function b(){
             var go="e~~";
                    this.a
    ="hi";
                }
                var t
    =new b();
                var n
    =new f();
                n.d.call(t);

    上面的代码会输出go hi

    说明代码的运行空间还是在f 函数中,但this已经被替换成 b的实例了

    这个要注意下,f里的d方法d并不是完全变为b的方法,只是将f中的方法中的实例换成b的实例,然后在运行f里的d方法,f环境里定义的变量在f里的d是完全可用的,由于f里的d方法的this被b对象替换,所有f里的d方法访问的是b对象来的,但对于b对象而言,并未增加新的方法

    通过上面的解释来做继承实现

    代码
    function a(v){   
       
    this.a=v;   
    }   
    function b(v){   
        
    this.b="test2";    
        a.apply(
    this,new Array(v)); 
        
    //apply意思是将a类里的this用b对象替换,参数传递通过第二个数组参数 
    }   
    var c=new b();   
    alert(c.a);   
    alert(c.b); 

    总结出一个方便记忆的方法:可以把apply或call看成的替换,用apply或call的时候的意思是要把当前Function对象里的this(就是对象本身)用指定的对象替换,如果被当前Function对象里有this.a=funtion(){}或this.b="hi",因为调用apply或call的时候在运行该方法,也就等于在指定的对象上增加新的属性或方法(和 指定的对象.a=function(){}或指定的对象.b="hi"的意思一样),从而指定的对象里也就增加了这个方法或属性,如果没有,定的对象的也就没有新的属性或方法添加,实现继承的原理就是这样的.

    call apply 是对Function对象而言,而Object对象本身没有这两个函数,如下例:

    function a(){
            
    this.f=function(){alert("af");}
        }
        
    function b(){
        
        }
        
    var oa=new a();
        
    var ob=new b();
        oa.call(ob);//错误的~~
      a.call(ob);//正确
        ob.f();
      //或者
      oa.f.call(ob);//正确,加往f里加this.f=function(){alert('aff');} 后调用ob.f();//out aff

     从本质上来看apply和call方法只为了实现方法重用,JS的OO还是挺强的~

     接着上面的,实现重写:
     

    代码
        function a(){
            
    this.f=function(){
                alert(
    "af");
            };
            
    this.c=function(){
                alert(
    "ac");
            }
        }
        
    function b(){
            a.call(
    this);
            
    var bf=this.f;
            
    this.f=function(){
                bf();
    //调用父类方法
                alert("bf")
            };
        }
        
    var ob=new b();
        ob.f();
        ob.c();

     实现重载:

    代码
    //示例1:
    function a(){
            
    var _f1=function(v1){
                alert(v1);
            }
            
    var _f2=function(v1,v2){
                alert(v1);
            }
            
    this.f=function(){
                
    switch(typeof(arguments[0])){
                    
    case 'number':
                        _f1(arguments[
    0]);
                    
    break;
                    
    case 'string':
                        _f2(arguments[
    0]);
                    
    break;
                }
            };
        }
        
    var oa=new a();
        oa.f(
    1);
        oa.f(
    "string");
    //示例2:
        function a(){
            
    var _f1=function(v1){
                alert(v1);
            }
            
    var _f2=function(v1,v2){
                alert(v1);
                alert(v2);
            }
            
    this.f=function(){
                
    switch(arguments.length){
                    
    case 1:
                        _f1(arguments[
    0]);
                    
    break;
                    
    case 2:
                        _f2(arguments[
    0],arguments[0]);
                    
    break;
                }
            };
            
    this.c=function(){
                alert(
    "ac");
            }
        }
        
    var oa=new a();
        oa.f(
    1);
        oa.f(
    1,2);

     函数中的caller属性

    这个属性在函数体上表示调用该函数的函数代码,如下例

     function callerDemo() {
        if (callerDemo.caller) {
            var a= callerDemo.caller.toString();
            alert(a);
        } else {
            alert("this is a top function");
        }
    }
    function handleCaller() {
        callerDemo();
    }
    handleCaller();

    会打印出:

    function handleCaller() {
        callerDemo();
    }

    对象:callee

    callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用

    其中arguments.callee.length是形参长度


    普通对象转为函数对象后使用call

    (function(){'ddd':'dddd'}).call({})

  • 相关阅读:
    BZOJ2962: 序列操作
    BZOJ2037: [Sdoi2008]Sue的小球
    LOJ#2537. 「PKUWC2018」Minimax
    LOJ#2538. 「PKUWC2018」Slay the Spire
    BZOJ4756 [USACO17JAN]Promotion Counting晋升者计数
    BZOJ2212——线段树合并
    atcoder.keyence2019.contest E-Connecting Cities
    [转载]笛卡尔树
    大数模板
    点分治
  • 原文地址:https://www.cnblogs.com/liushannet/p/1863999.html
Copyright © 2011-2022 走看看