`

函数的参数arguments、当前上下文this、call apply

 
阅读更多
函数的参数arguments
js中的各式“伪数组”,如arguments、与dom有关的childNodes等,这些对象虽然也有length属性,也可以通过数字下标索引元素,但它们不是Array对象,而是Object对象,通过它们的constructor属性就可以很清晰的判断出来了。
javascript在处理函数的参数时,与其他编译型的语言不一样。在javascript中,解释器传递给函数的是一个类似于数组的内部值,叫arguments,这个在函数对象生成的时候就被初始化了。先通过一个例子来讨论这个神奇的arguments:
function sum(){
    var len = arguments.length
    for(var i=0; i<len; i++){
        alert(arguments[i]); //查看arguments伪数组
    }

    var result = 0;   
    for(var i=0; i<len; i++){   
       var current = arguments[i];   
       if(isNaN(current)){
           throw new Error("not a number exception");   
       }else{  
           result += current;   
       }
    }
    return result;   
}
sum(); //此时sum方法中,arguments为空数组,arguments.length=0
sum(10, 20, 30, 40); //数组arguments.length=4   返回结果100
sum(4, 8, 15, 16, 23, 42);//数组arguments.length=6   108
sum("new");//数组arguments.length=1  报错Error: not a number exception

运行结果可以看出:函数sum并没有定义显式的形参,而我们又可以动态的传递给其任意多的参数,那么,如何在sum函数中如何引用这些参数呢?这里就需要用到arguments这个对象。
再看个例子:
function f(x,y){
    alert(x+"   ===   "+y);
    var len = arguments.length
    for(var i=0; i<len; i++){
        alert(arguments[i]); //查看arguments数组
    }
}
f(1); 
f(1,2);
f(1,2,3); 
//运行结果表明:如果声明时函数的参数小于传进来的参数个数,那么在函数体内部可以使用arguments获得其他的参数

//给函数传了一个叫a的参数,并且只有这一个参数,那么a与arguments[0]都是对这个参数值的引用,改变其中一个值,即改变了二者所有的值
function change(a){
    alert(a);   //比如我传的a为gerry,那么alert就是gerry;如果啥也没传就会alert undefined
    arguments[0]='xiaoxiaozi';   //用arguments[0]改变了这个参数的值
    alert(a);    //没错,这个值变成了xiaoxiaozi
}

//阶乘方法:n*(n-1)*(n-2)*...*3*2*1   
function factorial(n){ 
    if(n == 1){   
        return 1;   
    }else{   
        return n * factorial(n - 1);   
    }   
}
//改为三元实现:
function factorial(n){   
    return n==0 ? 1 : n * factorial(n-1);     
}  
//匿名调用:
(function(x){   
  return x == 0 ? 1 : x * arguments.callee(x-1);   
})(10);//3628800  
其中,arguments.callee表示函数本身,也就是被调用者。caller是调用者
callee :返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。 
caller :返回一个对函数的引用,该函数调用了当前函数。这个才是调用者


当前上下文this、call apply
方法(Method)本身就是是函数(function),只不过方法的使用更受限制。
我们知道,每一个对象都包含0个或多个属性,属性可以是任意类型,当然也包括对象。函数本身就是一种对象,因此我们完全可以把一个函数放到一个对象里面,此时,这个函数就成了对象的一个方法。此后如果要使用该方法,则可以通过对象名利用"."操作符来实现。
方法的调用需要对象的支持,那么在方法中如何获取对象呢?this!this关键字表示调用该方法的对象,也就是说通过对象调用方法的时候,this关键字会指向该对象。例如:
domObj.onclik = function(){
    clickFun(this);//onclick是对象domObj的方法,故这里的this就是domObj
}
在javascript中,this表示当前上下文,即调用者的引用(this表示对方法调用者(对象)的引用)。this的值并非函数如何被声明而确定,而是被函数如何被调用而确定,这一点与传统的面向对象语言截然不同。函数的上下文是可以变化的,因此,函数内的this也是可以变化的,函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,总之,this只是在任意对象和function元素结合时的一个概念,函数本身是独立的。可以通过Function对象上的call或者apply函数来修改函数的上下文。
call和apply是Function上的函数,通常用来修改函数的上下文,函数中的this指针将被替换为call或者apply的第一个参数,例如:
var name = "the name of window";//定义一个全局变量,name
var jack = {   //定义一个人,名字为jack
    name : "jack",   
    age : 26   
}
var gerry = {  //定义另一个人,名字为gerry
    name : "gerry",   
    age : 25   
}
function printName(){  //定义一个全局的函数对象
    return this.name;   
}   
    
//设置printName的上下文为jack, 此时的this为jack   
alert(printName.call(jack));   
//设置printName的上下文为gerry,此时的this为gerry
alert(printName.call(gerry));   
//设置printName的上下文为window,此时的this为window,打印"the name of window"
alert(printName.call(window));
//直接调用函数,此时即:调用window对象的printName方法。调用window对象的属性或者方法时,可以省略window对象,直接调用。也打印"the name of window"
printName();
 
//改为apply实现:
alert(printName.apply(jack));   
alert(printName.apply(gerry));  
 
只有一个参数的时候call和apply的使用方式是一样的,如果有多个参数时,apply的第二个参数为函数需要的参数组成的一个数组,而call则直接跟若干个参数,参数之间以逗号(,)隔开:
setName.apply(jack, ["tom"]);   
alert(printName.apply(jack));   //打印tom
    
setName.call(gerry, "gerry wang");   
alert(printName.call(gerry));  //打印gerry wang


参考:http://abruzzi.iteye.com/博客中的“javascript内核系列”
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics