這是一道面試題, 請先思考,在看講解 :)
var param = 1; function main() { console.log(param); var param = 2; console.log(this.param); this.param = 3; } //下面兩條語句分別會在控制台打印什麼? main(); var m = new main();
講解如下:
1. main() , 打印的結果為: undefined , 1
a. > 來看第一個打印的值為什麼是 undefined。 在js中,方法和變量的聲明都是會提前的。也就是說不管你在何處聲明的方法或者變量,在js解析時,都會將其提前,具體看代碼
demo(); //此處能正常彈出 similar function demo() { alert("similar"); }
按照js的語句執行順序,應該是從上自下依次執行的。 也就是說會先執行demo(), 然而這個時候demo()還沒有聲明,並不存在,應該報錯才對,為什麼還能正常彈出similar呢?這就前面說的方法聲明在js解析時會提前。所以上面的代碼,經過解析之後,就相當於
function demo() { alert("similar"); } demo(); //此處能正常彈出 similar
所以才會正常彈出 similar。 那麼對於變量的聲明也是一樣的,會提前。 我們上面的代碼,經過解析之後實際上等同於下面的代碼
var param; //聲明提前 param = 1; function main() { var param; //聲明提前 console.log(param); //因為此時 param 只是進行了聲明,並未賦值,所以 打印的是 undefined param = 2; console.log(this.param); this.param = 3; }
這裡你或許會感到疑惑。我們在main()方法外面不是已經賦值為1了嗎? 這是因為,我們在main()方法裡面也定義了一個同名的 param。 就近原則,js會先查找自己有沒有這個變量,如果有,就用自己的,如果沒有就向上級查找,上級還有沒有就到上上級去查找,如此循環,在哪找到,就在哪停止。如果全都沒有,就返回undefined。 【這裡涉及到一個知識點: js作用域鏈及變量查找, 之後我會寫一篇於此相關的講解文章】
b. > 現在我們再來看看第二打印的值為什麼是1。 我將代碼再做一次等價轉換,這樣或許大家就更容易明白緣由了,轉換後代碼如下
window.param = 1; //全局變量 param // 全局方法 main() window.main = function () { console.log(param); var param = 2; console.log(this.param); //此時的this指代的就是 window, 因此 this.param = window.param = 1 this.param = 3; }
//調用全局方法main() window.main();
看到這裡,大家是否有些明白了呢?因為 main() 方法和 main() 方法外面的 param 都是定義在最外層的(沒有包裹在其他對象裡面),因此他們都是全局對象window下的成員。 當我們調用 main() 方法時, 實際上就是調用的 window.main(); 而通過這樣的方式調用時, this 指代的就是全局對象 window。 所以第二個打印的值為 1。【這裡涉及到一個知識點: js中讓人迷糊的this,之後我會寫一篇於此相關的講解文章】
2. var m = new main(), 打印的結果為: undefined, undefined
a. > 第一個打印的值為 undefined 的原因和上面的原因是一樣的,都是因為變量聲明提前導致的。
b. > 那麼第二個打印的值也為 undefined 的原因是什麼呢? Js也是支持面向對象式編程的語言,然而js中卻沒有類的概念,而是使用基於原型(prototype)的繼承。 因此呢,js中的構造函數也很特別,一般情況下它和普通方法沒什麼區別,只有通過 new 關鍵字來調用的時候才能體現出其作為構造函數的功能。 而此處正是把 main() 和 new 關鍵字一起使用,說明此時的main()是一個構造函數。而構造函數中的 this 指代的就是新創建的對象,那麼也就是 m 。
var param = 1; function main() { var param; //聲明提前 console.log(param); //因為此時 param 只是進行了聲明,並未賦值,所以 打印的是 undefined param = 2; console.log(this.param); //構造函數中的this指代的是新創建的對象,我們這裡新創建的對象是 m , 所以 this.param = m.param , 而此時 this.param 尚未賦值,所以打印的是 undefined (此處我自己也有一個疑問: 構造函數中的屬性的聲明會提前嗎?也就是 this.param 的聲明會提前嗎? 求解) this.param = 3; } var m = new main();
說到底這裡還是一個關於 js 中 this 的理解的問題,掌握了this , 此問題就很好理解了。現在都知道各中緣由了,是不是有種豁然開朗的感覺,哈哈...