注:在閱讀本博文前請先閱讀《理解javascript_13_執行模型詳解》
注:本文的部分內容是自已的一些推論,並無官文文檔作依據,如有錯誤之後,還望指正。
生澀的代碼
我們先來看一段比較生澀的代碼:
復制代碼 代碼如下:
function say(msg,other,garbage){
alert(arguments[1]);//world
var other = 'nice to meet you!';
var msg;
alert(arguments.length);
alert(msg);//hello
alert(other);//nice to meet you!
alert(arguments[1]);//nice to meet you!
alert(garbage);//undefined
}
say('hello','world');
你能正確的解釋代碼的執行結果嗎?思考一下. 我想代碼運行的結果,應該會和你的想象有很大的出入吧!為什麼msg正常輸出為hello,而不是undefined呢?函數定義的參數和函數內部定義的變量重復了會發生什麼呢?arguments和函數定義時的參數有什麼關系呢?讓我們來一一解答:
簡單的內存圖
注:虛線表示的是曾經引用的指向。
解答
首先,我們來了解兩個概念,形式參數和實際參數。形式參數指的是定義方法時所明確指定的參數,由於Javascript語言的靈活性,javascript並不要求方法調用時,所傳遞的參數個數與形式參數一致.而javascript實際調用時所傳遞的參數就是實際參數。arguments指的就是實際參數。從say方法中可以看出,say定義了三個形式參數,而實際調用時只傳遞了兩個值。因此arguments.length的值為2,而不是3.接著我們來看一下arguments的特殊行為,個人感覺arguments會將所有的實際參數都當作對象來看待,對於基本數據類型的實際參數則會轉換為其對應的對象類型。這是根據在函數內定義與形式參數同名的變量並賦值,arguments對應的值會跟著改變來判斷的。
接著我們來分析一下構建say方法執行上下文的過程,由於邏輯比較復雜,這裡我寫一些'偽代碼'來進行說明:
復制代碼 代碼如下:
function say(msg,other,garbage){
//先對函數聲明的變量進行'預解析',內部執行流程,它是是不可見的
var msg = undefined;
var other = undefined;
var garbage = undefined;
//再對函數內部定義的變量進行'預解析'
var other = undefined;//很明顯,此時這個定義已經無意義了。
var msg = undefined;//無意義
//對實際參數進行賦值操作
msg = new String('hello');//arguments的會將所有實際參數當作對象看待
other = new String('world');
//正式進入函數代碼部分
alert(arguments[1]);//world
other = 'nice to meet you!';
//var msg;這個已經被預解析了,因此不會再執行
alert(arguments.length);//2
alert(msg);//hello
alert(other);//nice to meet you!
alert(arguments[1]);//nice to meet you!
alert(garbage);//undefined
}
這段代碼已經可以解釋一面的所有的問題了。我就不多說了。
唯一強調的一點是在內部用var定義與形式參數同名的變量是無意義的,因為在程序'預解析'後,會將它們看作為同一個變量。
其它
關於arguments還有很多特性,我在《偽數組》一文中提到也提到了arguments,有興趣的讀者可以去看一下。arguments的實際應用你還可以參考一下這一篇文章 :
http://www.gracecode.com/archives/2551/
好了,也就這麼多了。希望大家能多多指正,多提意見吧。