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的應用場景 主要用於察看函數自己被哪一個函數調用。

相關文章
相關標籤/搜索