1.JavaScript hoisting(變數/函數 提升)
以下實驗都是通過firefox的Console做的實驗. console.log(a); ReferenceError: a is not defined
但是,如果在後面加上變數的定義的話,結果將會變得不同.
console.log(a); var a = 10; undefined
之前變數沒有定義的錯誤沒了,取而代之的是告訴我們a的值是 'undefined'.
先不管a的值緣何為 'undefined' 了,至少可以知道現a這個變數是定義了,因為之前報的' a is not defined'的錯誤沒有了。
這正是因為JavaScript 中的一個聲明提升的特性起的作用。
JavaScript中可以提前使用在後面語句中聲明的變數,這種特性叫被國外某網友(ben cherry)稱為Hoisting (非官方術語) 。
我在<<javascript 模式>> 一書中看到該詞被翻譯為 "提升" ,指的的就是變數聲明提前 .可以理解為將變數的聲明提前了,所以在變數聲明前使用變數不會報錯。而且這一特性不僅限於變數名,對於函數的聲明也是同樣的效果。
第一次對函數foo()的調用同樣報 'not defined' 錯誤。這是合情合理同時是合法的。因為從頭到尾就沒有定義這麼一個叫作foo() 的東西。
ReferenceError: foo is not defined
之後將函數調用寫在最前面,但函數的定義我們寫在了之後。
foo(); function foo(){ console.log("I am foo"); } I am foo
發現正常輸出了我們想要的內容.
這裡需要深入理解Hoisting這一特性。它的提前只是將聲明提前,而對變數的賦值並沒有跟著提前。
也就是為什麼我們可以在第一句使用變數a但它的值卻是 'undefined'。 JavaScript裡面聲明了但還未賦值的變數其值預設便是 'undefined'。
按照Hoisting來解釋,最終產生的等價代碼其實差不多應該就是這樣的:
var a ;
console.log(a);
a = 1;
1.匿名函數無法在聲明前調用
SyntaxError: missing ( before formal parameters
|
foo1();var foo1 = function{ console.log("I am foo1");} |
正如上面介紹的Hoisting特性,函數可以定義在調用之前也可以定義在調用之後:
但僅限於上述這種方式定義的函數。對於匿名函數上述規則不適用。
2. 參數變更影響到函數外部
當傳遞給函數的參數是一個數組或對象時,在函數體內對這個傳入的參數的更改會影響到函數體外的原傳入值。
一般說來,對參數的更改不會影響到原來變數的值,更改只在函數體內起作用,這個主要原因是javascript變數傳遞都是按值傳遞的.將變數的值進行複製,然後傳入到函數內部處理.但是對於對象和數組則有所不同.
當傳入的參數是數組、對象時,在函數體內對參數所做的更改會反映到原變數上。
function myFunc(theObject) { theObject.make = "Toyota";}var mycar = {make: "Honda", model: "Accord", year: 1998}, x, y;x = mycar.make; // x gets the value "Honda"myFunc(mycar);y = mycar.make; // y gets the value "Toyota" // (the make property was changed by the function)console.log(x );console.log(y);
可以看出,上面代碼中已經把mycar 對象的make屬性修改了.
當在函數體內對傳入的數組或對象賦值時,這個更改不會反映到函數體外的原變數身上 下面是關於對象的例子:
function myFunc1(theObject) { theObject = {make: "Ford", model: "Focus", year: 2006};}var mycar = {make: "Honda", model: "Accord", year: 1998}, x, y;x = mycar.make; // x gets the value "Honda"myFunc1(mycar);y = mycar.make; // y still gets the value "Honda"console.log(x);console.log(y);
按照上面函數內部的更改會反映到原變數的理論。但結果讓人有點難以接受。
真的,我內心真的"此起彼伏"啊.
原因在於,當在函數體內使用賦值操作時,系統就建立了一個變數名為theObject的變數。這個theObject是函數內部的變數,對它進行賦值當然只在函數體內起作用,外面的myCar還是原來的myCar。
這一步與原來代碼的操作差別僅在於在函數體內是對參數賦新值呢還是對參數的屬性或數組的元素變更。
以上內容來自MDN 中關於javascript的文章.連結地址為:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Best wishes.