【轉(zhuǎn)】你真的明白JavaScript了么

來自 So, you think you know JavaScript?
-- 著名前端架構(gòu)師Baranovskiy

  • 題目1

    var a = 'he';

    if (!("a" in window)) {
        var a = 1;
    }
    alert(a);
    
  • 題目二
    var a = 1,
    b = function a(x) {
    x && a(--x);
    };
    alert(a);

  • 題目三

     function a(x) {
         return x * 2;
     }
     var a;
     alert(a);
    
  • 題目四:
    function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
    }
    b(1, 2, 3);

  • 題目五:
    function a() {
    alert(this);
    }
    a.call(null);
    請不要借助任何幫助工具,心算答案。答案在下面。

答案

題目1

if (!("a" in window)) {
    var a = 1;
}
alert(a);

代碼含義:如果window不包含屬性a,就聲明一個變量a,然后賦值為1。
你可能認為alert出來的結(jié)果是1,然后實際結(jié)果是“undefined”。要了解為什么,需要知道JavaScript里的3個概念。
首先,所有的全局變量都是window的屬性,語句 var a = 1;等價于window.a = 1; 你可以用如下方式來檢測全局變量是否聲明:

"變量名稱" in window

第二,所有的變量聲明都在范圍作用域的頂部,看一下相似的例子:

alert("a" in window);
var a;

此時,盡管聲明是在alert之后,alert彈出的依然是true,這是因為JavaScript引擎首先會掃墓所有的變量聲明,然后將這些變量聲明移動到頂部,最終的代碼效果是這樣的:

var a;
alert("a" in window);

這樣看起來就很容易解釋為什么alert結(jié)果是true了。
第三,你需要理解該題目的意思是,變量聲明被提前了,但變量賦值沒有,因為這行代碼包括了變量聲明和變量賦值。
你可以將語句拆分為如下代碼:

var a;    //聲明
a = 1;    //初始化賦值

當(dāng)變量聲明和賦值在一起用的時候,JavaScript引擎會自動將它分為兩部以便將變量聲明提前,不將賦值的步驟提前是因為他有可能影響代碼執(zhí)行出不可預(yù)期的結(jié)果。
所以,知道了這些概念以后,重新回頭看一下題目的代碼,其實就等價于:

var a;
if (!("a" in window)) {
    a = 1;
}
alert(a);

這樣,題目的意思就非常清楚了:首先聲明a,然后判斷a是否在存在,如果不存在就賦值為1,很明顯a永遠在window里存在,這個賦值語句永遠不會執(zhí)行,所以結(jié)果是undefined。
提前這個詞語顯得有點迷惑了,你可以理解為:預(yù)編譯。

  • 題目2
var a = 1,
    b = function a(x) {
        x && a(--x);
    };
alert(a);

這個題目看起來比實際復(fù)雜,alert的結(jié)果是1;這里依然有3個重要的概念需要我們知道。
首先,在題目1里我們知道了變量聲明在進入執(zhí)行上下文就完成了;第二個概念就是函數(shù)聲明也是提前的,所有的函數(shù)聲明都在執(zhí)行代碼之前都已經(jīng)完成了聲明,和變
量聲明一樣。澄清一下,函數(shù)聲明是如下這樣的代碼:

function functionName(arg1, arg2){
    //函數(shù)體
}

如下不是函數(shù),而是函數(shù)表達式,相當(dāng)于變量賦值:

var functionName = function(arg1, arg2){
    //函數(shù)體
};

澄清一下,函數(shù)表達式?jīng)]有提前,就相當(dāng)于平時的變量賦值。
第三需要知道的是,函數(shù)聲明會覆蓋變量聲明,但不會覆蓋變量賦值,為了解釋這個,我們來看一個例子:

function value(){
    return 1;
}
var value;
alert(typeof value);    //"function"

盡快變量聲明在下面定義,但是變量value依然是function,也就是說這種情況下,函數(shù)聲明的優(yōu)先級高于變量聲明的優(yōu)先級,但如果該變量value賦值了,那結(jié)果就完全不一樣了:

function value(){
    return 1;
}
var value = 1;
alert(typeof value);    //"number"

該value賦值以后,變量賦值初始化就覆蓋了函數(shù)聲明。
重新回到題目,這個函數(shù)其實是一個有名函數(shù)表達式,函數(shù)表達式不像函數(shù)聲明一樣可以覆蓋變量聲明,但你可以注意到,變量b是包含了該函數(shù)表達式,而該函數(shù)表達式的名字是a;不同的瀏覽器對a這個名詞處理有點不一樣,在IE里,會將a認為函數(shù)聲明,所以它被變量初始化覆蓋了,就是說如果調(diào)用a(–x)的話就會出錯,而其它瀏覽器在允許在函數(shù)內(nèi)部調(diào)用a(–x),因為這時候a在函數(shù)外面依然是數(shù)字?;旧?,IE里調(diào)用b(2)的時候會出錯,但其它瀏覽器則返回undefined。
理解上述內(nèi)容之后,該題目換成一個更準(zhǔn)確和更容易理解的代碼應(yīng)該像這樣:

var a = 1,
    b = function(x) {
        x && b(--x);
    };
alert(a);

這樣的話,就很清晰地知道為什么alert的總是1了。

  • 題目3
function a() {
    return 1 ;
}
var a;
alert(a);

這個題目比較簡單:即函數(shù)聲明和變量聲明的關(guān)系和影響,遇到同名的函數(shù)聲明,不會重新定義

  • 題目4
function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);

關(guān)于這個題目,ECMAsCRIPT 262-3的規(guī)范有解釋的。
活動對象是在進入函數(shù)上下文時刻被創(chuàng)建的,它通過函數(shù)的arguments屬性初始化。arguments屬性的值是Arguments對象.
關(guān)于 Arguments對象的具體定義,看這里:ECMAScript arguments 對象

  • 題目5
function a() {
    alert(this);
}
a.call(null);

這個題目可以說是最簡單的,也是最詭異的!關(guān)于這個題目,我們先來了解2個概念。
這個問題主要考察 Javascript 的 this 關(guān)鍵字,具體看這里:
關(guān)于Javascript語言中this關(guān)鍵字的用法

關(guān)于 a.call(null); 根據(jù)ECMAScript262規(guī)范規(guī)定:如果第一個參數(shù)傳入的對象調(diào)用者是null或者undefined的話,call方法將把全局對象(也就是window)作為this的值。所以,不管你什么時候傳入null,其this都是全局對象window,所以該題目可以理解成如下代碼:

function a() {
    alert(this);
}
a.call(window);

所以彈出的結(jié)果是[object Window]就很容易理解了。

—————
總結(jié):
這5個題目雖然貌似有點偏,但實際上考察的依然是基本概念,只有熟知了這些基本概念才能寫出高質(zhì)量代碼。

var a = 'hello'

[TOC]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 來源:仗劍走天涯! 關(guān)于javascript的作用域的一些總結(jié),主要參考以上文章,加上自己的整理的理解。 近日對j...
    Michael_林閱讀 1,021評論 0 1
  • 第一章: JS簡介 從當(dāng)初簡單的語言,變成了現(xiàn)在能夠處理復(fù)雜計算和交互,擁有閉包、匿名函數(shù), 甚至元編程等...
    LaBaby_閱讀 1,759評論 0 6
  • 深入理解JavaScript系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,如果對你有用,請推薦支持一把,給大...
    DaveWeiYong閱讀 707評論 0 1
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,677評論 0 4
  • 最近的高額轉(zhuǎn)會費總讓人懷疑。轉(zhuǎn)會費在對外支出序列是經(jīng)常項目,尚無臨時管制措施出臺……
    怪物辦公室閱讀 224評論 0 0

友情鏈接更多精彩內(nèi)容