第4章 變數 作用域和記憶體問題(2)

2021-07-25 13:42:51 字數 2879 閱讀 6001

4.1.3 傳遞引數

ecmascript 中所有函式的引數都是按值傳遞的。也就是說,

把函式外部的值複製給函式內部的引數,就和把值從乙個變數複製到另乙個變數一樣。

基本型別值的傳遞如同基本型別變數的複製一樣,而引用型別值的傳遞,則如同引用型別變數的複製一樣。

有不少開發人員在這一點上可能會感到困惑,因為訪問變數有按值和按引用兩種方式,而引數只能按值傳遞。

在向引數傳遞基本型別的值時,被傳遞的值會被複製給乙個區域性變數(即命名引數,

或者用ecmascript 的概念來說,就是arguments 物件中的乙個元素)。在向引數傳遞引用型別的值時,會把

這個值在記憶體中的位址複製給乙個區域性變數,因此這個區域性變數的變化會反映在函式的外部。請看下面

這個例子:

這裡的函式addten()有乙個引數num,而引數實際上是函式的區域性變數。在呼叫這個函式時,變

量count 作為引數被傳遞給函式,這個變數的值是20。於是,數值20 被複製給引數num 以便在addten()

中使用。在函式內部,引數num 的值被加上了10,但這一變化不會影響函式外部的count 變數。引數

num 與變數count 互不相識,它們僅僅是具有相同的值。

假如num 是按引用傳遞的話,那麼變數count的值也將變成30,從而反映函式內部的修改。當然,使用數值等基本型別值來說明按值

傳遞引數比較簡單,但如果使用物件,那問題就不怎麼好理解了。再舉乙個例子:

以上**中建立乙個物件,並將其儲存在了變數person 中。然後,這個變數被傳遞到setname()

函式中之後就被複製給了obj。在這個函式內部,obj 和person 引用的是同乙個物件。換句話說,即

使這個變數是按值傳遞的,obj 也會按引用來訪問同乙個物件。於是,當在函式內部為obj 新增name

屬性後,函式外部的person 也將有所反映;因為person 指向的物件在堆記憶體中只有乙個,而且是全

局物件。有很多開發人員錯誤地認為:在區域性作用域中修改的物件會在全域性作用域中反映出來,就說明

引數是按引用傳遞的。為了證明物件是按值傳遞的,我們再看一看下面這個經過修改的例子:

function setname(obj) 

var person = new object();

setname(person);

alert(person.name); //"nicholas"

這個例子與前乙個例子的唯一區別,就是在setname()函式中新增了兩行**:一行**為obj

重新定義了乙個物件,另一行**為該物件定義了乙個帶有不同值的name 屬性。在把person 傳遞給

setname()後,其name 屬性被設定為"nicholas"。然後,又將乙個新物件賦給變數obj,同時將其name

屬性設定為"greg"。如果person 是按引用傳遞的,那麼person 就會自動被修改為指向其name 屬性值

為"greg"的新物件。但是,當接下來再訪問person.name 時,顯示的值仍然是"nicholas"。這說明

即使在函式內部修改了引數的值,但原始的引用仍然保持未變。實際上,當在函式內部重寫obj 時,這

個變數引用的就是乙個區域性物件了。而這個區域性物件會在函式執行完畢後立即被銷毀。

ps:可以把ecmascript 函式的引數想象成區域性變數。

4.1.4 檢測型別

要檢測乙個變數是不是基本資料型別?typeof 操作符是最佳的工具。說得更具體一點,

typeof 操作符是確定乙個變數是字串、數值、布林值,還是undefined 的最佳工具。如果變

量的值是乙個物件或null,則typeof 操作符會像下面例子中所示的那樣返回"object":

雖然在檢測基本資料型別時typeof 是非常得力的助手,但在檢測引用型別的值時,這個操作符的用處不大。

通常,我們並不是想知道某個值是物件,而是想知道它是什麼型別的物件。為此,ecmascript

提供了instanceof 操作符,其語法如下所示:

result = variable instanceof constructor

如果變數是給定引用型別(根據它的原型鏈來識別;第6 章將介紹原型鏈)的例項,那麼

instanceof 操作符就會返回true。請看下面的例子:

alert(person instanceof object); // 變數person 是object 嗎?

alert(colors instanceof array); // 變數colors 是array 嗎?

alert(pattern instanceof regexp); // 變數pattern 是regexp 嗎?

根據規定,所有引用型別的值都是object 的例項。因此,在檢測乙個引用型別值和object 構造

函式時,instanceof 操作符始終會返回true。當然,如果使用instanceof 操作符檢測基本型別的

值,則該操作符始終會返回false,因為基本型別不是物件。

ps:使用typeof 操作符檢測函式時,該操作符會返回"function"。在safari 5 及

之前版本和chrome 7 及之前版本中使用typeof 檢測正規表示式時,由於規範的原

因,這個操作符也返回"function"。ecma-262 規定任何在內部實現[[call]]方法

的物件都應該在應用typeof 操作符時返回"function"。由於上述瀏覽器中的正則

表示式也實現了這個方法,因此對正規表示式應用typeof 會返回"function"。在

ie 和firefox 中,對正規表示式應用typeof 會返回"object"。

變數 作用域和記憶體問題

1.1 動態的屬性 引用型別 var person new object person.name nicholas alert person.name nicholas 基本型別 var name nicholas name.age 27 alert name.age undefined1.2 複製...

JS 變數 作用域和記憶體問題

向引數傳遞基本型別時 把值從乙個變數賦值到另乙個變數 傳遞引用型別時 把這個值在記憶體中的位址賦值給區域性變數 function addten num var count 20 var result addten count console.log count 20,沒有變化 console.log...

js 變數 作用域和記憶體問題

基本型別和引用型別 屬性引用型別可以動態新增屬性,而基本型別不可以 var p new obj p.name huyuping console.log p.name huyuping var a a.name huyuping console.log a,name 出錯複製變數值 會在變數的物件上建...