js apply,call,arguments,callee,caller详解

apply与call

主要解决一下几个问题:javascript

1.apply和call的区别在哪里java

2.什么状况下用apply,什么状况下用call数组

3.apply的其余巧妙用法(通常在什么状况下可使用apply)网络

    apply:方法能劫持另一个对象的方法,继承另一个对象的属性.app

Function.apply(obj,args)方法能接收两个参数函数

obj:这个对象将代替Function类里this对象测试

args:这个是数组,它将做为参数传给Function(args-->arguments)this

         call:和apply的意思同样,只不过是参数列表不同.spa

 Function.call(obj,[param1[,param2[,…[,paramN]]]])prototype

obj:这个对象将代替Function类里this对象

params:这个是一个参数列表

1.apply示例:

<script type="text/javascript">  
    /*定义一我的类*/  
    function Person(name,age)  
    {  
        this.name=name;  
        this.age=age;  
    }  
    /*定义一个学生类*/  
    functionStudent(name,age,grade)  
    {  
        Person.apply(this,arguments);  
        this.grade=grade;  
    }  
    //建立一个学生类  
    var student=new Student("zhangsan",21,"一年级");  
    //测试  
    alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
    //你们能够看到测试结果name:zhangsan age:21  grade:一年级
    //学生类里面我没有给name和age属性赋值啊,为何又存在这两个属性的值呢,这个就是apply的神奇之处.  
</script>

分析: Person.apply(this,arguments);

this:在建立对象在这个时候表明的是student

arguments:是一个数组,也就是[“zhangsan”,”21”,”一年级”];

                   也就是通俗一点讲就是:用student去执行Person这个类里面的内容,在Person这个类里面存在this.name等之类的语句,这样就将属性建立到了student对象里面

 

2.call示例

在Studen函数里面能够将apply中修改为以下:

Person.call(this,name,age);

这样就ok了

3.什么状况下用apply,什么状况下用call

在给对象参数的状况下,若是参数的形式是数组的时候,好比apply示例里面传递了参数arguments,这个参数是数组类型,而且在调用 Person的时候参数的列表是对应一致的(也就是Person和Student的参数列表前两位是一致的) 就能够采用 apply , 若是个人Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就能够用call来 实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));

4.apply的一些其余巧妙用法

细心的人可能已经察觉到,在我调用apply方法的时候,第一个参数是对象(this), 第二个参数是一个数组集合, 在调用Person的时候,他须要的不是一个数组,可是为何他给我一个数组我仍然能够将数组解析为一个一个的参数,这 个就是apply的一个巧妙的用处,能够将一个数组默认的转换为一个参数列表([param1,param2,param3] 转换为 param1,param2,param3) 这个若是让咱们用程序来实现将数组的每个项,来装换为参数的列表,可能都得费一会功夫,借助apply的这点特性,因此就有了如下高效率的方法:

a)Math.max 能够实现获得数组中最大的一项

由于Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组

可是它支持Math.max(param1,param2,param3…),因此能够根据刚才apply的那个特色来解决 var max=Math.max.apply(null,array),这样轻易的能够获得一个数组中最大的一项(apply会将一个数组装换为一个参数接一个参数的传递给方法)

         这块在调用的时候第一个参数给了一个null,这个是由于没有对象去调用这个方法,我只须要用这个方法帮我运算,获得返回的结果就行,.因此直接传递了一个null过去

b)Math.min  能够实现获得数组中最小的一项

一样和 max是一个思想 var min=Math.min.apply(null,array);

c)Array.prototype.push 能够实现两个数组合并

一样push方法没有提供push一个数组,可是它提供了push(param1,param,…paramN) 因此一样也能够经过apply来装换一下这个数组,即:

vararr1=new Array("1","2","3");    
vararr2=new Array("4","5","6");   
Array.prototype.push.apply(arr1,arr2);

也能够这样理解,arr1调用了push方法,参数是经过apply将数组装换为参数列表的集合.

一般在什么状况下,可使用apply相似Math.min等之类的特殊用法:

通常在目标函数只须要n个参数列表,而不接收一个数组的形式([param1[,param2[,…[,paramN]]]]),能够经过apply的方式巧妙地解决这个问题!

arguments

一、在JavaScript中,arguments对象是比较特别的一个对象,其实是 当前函数的一个内置属性。arguments很是相似Array,但实际上又不是一个Array实例。能够经过以下代码得以证明(固然,实际上,在函数 funcArg中,调用arguments是没必要要写成funcArg.arguments,直接写arguments便可)。

Array.prototype.testArg = "test";
function funcArg() { 
    alert(funcArg.arguments.testArg);
    alert(funcArg.arguments[0]); 
}

alert(new Array().testArg); // result: "test" 8 
funcArg(10); // result: "undefined" "10"

二、arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部从新开辟内存空间存储的变量,可是其与arguments对象 内存空间并不重叠。对于arguments和值都存在的状况下,二者值是同步的,可是针对其中一个无值的状况下,对于此无值的情形值不会得以同步。以下代 码能够得以验证。

function f(a, b, c){
    alert(arguments.length); // result: "2" 
    a = 100;
    alert(arguments[0]); // result: "100"
    arguments[0] = "qqyumidi";
    alert(a); // result: "qqyumidi"
    alert(c); // result: "undefined"
    c = 2012;
    alert(arguments[2]); // result: "undefined"
}

f(1, 2);

三、由JavaScript中函数的声明和调用特性,能够看出JavaScript中函数是不能重载的

根据其余语言中重载的依据:"函数返回值不一样或形参个数不一样",咱们能够得出上述结论:

第一:Javascript函数的声明是没有返回值类型这一说法的;

第二:JavaScript中形参的个数严格意义上来说只是为了方便在函数中的变量操做,实际上实参已经存储在arguments对象中了。

另外,从JavaScript函数自己深刻理解为何JavaScript中函数是不能重载的:在JavaScript中,函数其实也是对象,函数 名是关于函数的引用,或者说函数名自己就是变量。对于以下所示的函数声明与函数表达式,其实含以上是同样的(在不考虑函数声明与函数表达式区别的前提 下),很是有利于咱们理解JavaScript中函数是不能重载的这一特性。

function f(a){
    return a + 10;
}

function f(a){
    return a - 10;
}

// 在不考虑函数声明与函数表达式区别的前提下,其等价于以下

var f = function(a){
    return a + 10;
}

var f = function(a){
    return a - 10;
}

四、arguments对象中有一个很是有用的属性:callee。arguments.callee返回此arguments对象所在的当前函数引用。在使用函数递归调用时推荐使用arguments.callee代替函数名自己。

以下:

function count(a){
    if(a==1){
       return 1;
    }
    return a + arguments.callee(--a);
}

var mm = count(10);
alert(mm);

callee与caller

caller :

functionName.caller 返回调用者。

看看下面的函数,你们能够复制到VS中执行下

复制代码 代码以下:

function caller() {
    if (caller.caller) {
        alert(caller.caller.toString());
    } else {
        alert("函数直接执行");
    }
}

function handleCaller() {
    caller();
}

handleCaller();
caller();

你们会发现第一个alert会弹出调用caller函数的调用者handleCaller,而第二个alert因为没有在其余函数体内调用,因此caller为null,就执行了 alert("函数直接执行");

callee:

返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文.

callee是arguments 的一个属性成员,它表示对函数对象自己的引用,这有利于匿名

函数的递归或者保证函数的封装性。 下面一段代码先说明callee的用法,实例代码摘自网上

复制代码 代码以下:

function calleeLengthDemo(arg1, arg2) {
    alert(arguments.callee.toString());

    if (arguments.length == arguments.callee.length) {
        window.alert("验证形参和实参长度正确!");
        return;
    } else {
        alert("实参长度:" + arguments.length);
        alert("形参长度: " + arguments.callee.length);
    }
}

calleeLengthDemo(1);

第一个消息框弹出calleeLengthDemo函数自己,这说明callee就是函数自己对象的引用。callee还有个很是有用的应用就是用来判断实际参数跟行参是否一致。上面的代码第一个消息框会弹出实际参数的长度为1,形式参数也就是函数自己的参数长度为2.

应用场景:

callee的应用场景通常用于匿名函数

你们看下下面一段代码 摘自网络

复制代码 代码以下:

var fn=function(n){
    if(n>0) return n+fn(n-1);
    return 0;
}

alert(fn(10))

函数内部包含了对自身的引用,函数名仅仅是一个变量名,在函数内部调用即至关于调用

一个全局变量,不能很好的体现出是调用自身,这时使用callee会是一个比较好的方法

复制代码 代码以下:

var fn=(function(n){
    if(n>0) return n+arguments.callee(n-1);
    return 0;
})(10);

alert(fn)

这样就让代码更加简练。又防止了全局变量的污染。

caller的应用场景 主要用于察看函数自己被哪一个函数调用。

相关文章
相关标签/搜索