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({})

 

posted @ 2010-10-28 23:51  liushan  阅读(450)  评论(1编辑  收藏  举报