Dmitry Baranovskiy的javascript謎題

來源:互聯網
上載者:User

Dmitry Baranovskiy是何許人也?他是目前世界最優秀的JS開源圖形庫Raphaël的作者,還做了許多JS遊戲自娛,是JS界頂尖高手之一。

以下五道題是放於他的部落格上,直到另一個它們被另一個JS高手Nicholas C. Zakas(Yahoo!首頁首席前端工程師)提到,才迅速在網路蔓延開去。大家先試著自己做一下,想不明白才看解析吧。

     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);

第一題(請經過思考後再按運行框)

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>Dmitry Baranovskiy的javascript謎題 by司徒正美</title></p><p> <script type="text/javascript" charset="utf-8"></p><p>if (!("a" in window)) {<br /> var a = 1;<br />}<br />alert(a);</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />

運行代碼

第二題(請經過思考後再按運行框)

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>Dmitry Baranovskiy的javascript謎題 by司徒正美</title></p><p> <script type="text/javascript" charset="utf-8"></p><p> var a = 1,<br /> b = function a(x) {<br /> x && a(--x);<br /> };<br /> alert(a);</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />

運行代碼

第三題(請經過思考後再按運行框)

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>Dmitry Baranovskiy的javascript謎題 by司徒正美</title></p><p> <script type="text/javascript" charset="utf-8"></p><p>function a(x) {<br /> return x * 2;<br />}<br />var a;<br />alert(a);</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />

運行代碼

第四題(請經過思考後再按運行框)

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>Dmitry Baranovskiy的javascript謎題 by司徒正美</title></p><p> <script type="text/javascript" charset="utf-8"></p><p> function b(x, y, a) {<br /> arguments[2] = 10;<br /> alert(a);<br /> }<br /> b(1, 2, 3);</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />

運行代碼

第五題(請經過思考後再按運行框)

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>Dmitry Baranovskiy的javascript謎題 by司徒正美</title></p><p> <script type="text/javascript" charset="utf-8"></p><p>function a() {<br /> alert(this);<br />}<br />a.call(null);</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />

運行代碼

解釋

//第一題//undefined//★★考察javascript在先行編譯期幹了什麼javascript分兩個階段,先行編譯期與運行期先行編譯期,var 變數提前,術語為提前聲明。這時javascript引擎是從上到下,從外到內整塊地分析我們的源碼,構建文法樹。     if (!("a" in window)) {        var a = 1;    }    alert(a);由於javascript不存在塊範圍,因此if裡面的東西與if外面屬於同一個範圍。在先行編譯階段,var a被抽取出來,放到範圍的頂部。更專業的解釋可見ecma262r3,var 變數被放置到一個叫調用對象的東東中。那麼這時,我們的代碼就變成這樣   var a    if(!("a" in window)){         a = 1                }   alert(a)到運行期時,便開始從上到下,從裡到外執行那些修改過的指令碼。很明顯,"a" in window 為true ,再加個否定就為false,進不到if語句裡面了,當然alert undefined(凡是只聲明沒賦值的都會被自動賦上window的一個屬性undefined)//第二題 // 1//★★考察函式宣告,函數運算式與命名函數運算式這是函式宣告:function aa(){   alert("司徒正美!")}這是函數運算式:var bb = function(){     alert("司徒正美!!")}那這個算什嗎?        var cc = function dd(){          alert("司徒正美!!!")        }簡單,也是函數運算式,不過是叫命名函數運算式。但這東西並不統一,先說標準瀏覽器下,dd這個函數名只對其函數體內可見,因此外圍範圍一調用它就會出錯,因為它並不存在此引用(或叫變數吧)。這特性好像比較新的標準瀏覽器支援,如FF3+,safari3+(safari2有bug)。再回頭看IE,IE是支援這東西,還支援更多奇怪的寫法,如http://bbs.51js.com/viewthread.php?tid=86272&highlight=%2Binfinte但IE的命名函數運算式很顯然與標準的出入太大了。首先dd這函數名對函數的內外範圍是可見的,這很要命,很容易汙染全域範圍,造成的命名衝突,其次,它會建立兩個對象,cc是一個,dd是一個,修改其中一個會不會同步更新另一個,是記憶體流失的根源之一。命名函數運算式在IE中也作為函式宣告,換言之它會在先行編譯階階就會幹掉我們的同名函式宣告,你怎樣調試也打不出原因,因為調試是在運行期啟動並執行……嘛,由於這個alert是位於外圍範圍,因此在標準瀏覽器,我們的代碼可以看作是這樣:   var  a = 1;   var  b = function (x) {        x && a(--x);    };    alert(a);因此是1在IE中,先行編譯階段,其實有兩個a,不過沒有關係,反正前面的會覆蓋後面的,然後到運行期,a會賦予1,這時它不會賦給另一個函數對象,因為另一個a已在先行編譯階段就被幹掉了。換言之,這次很幸運避免了建立兩個函數對象,於是alert(1)。但命名函數運算式在IE下的糟糕表現,我們還是避免使用它吧,要想在內部調用自身,arguments.callee完成能勝任。//第三題//彈出函數的toString(),即//function a(x) {//    return x * 2;//}思路基本同第一題,var變數聲明在先行編譯階段被提前了,然後被重寫。var a;function a(x) {    return x * 2;}alert(a);//第四題//10//★★考察arguments對象在執行一個函數前,它會把它自身(callee),它的運行環境(callee.caller),傳入參數的個數,構建成一個argument對象,接著就像數組一樣,把參數一個個塞進argument中。運行時,如果某個參數被修改了,arguments對應的值也同步更新。理解這些就簡單了。原函數的意思是傳入三個參數,內部會把第三個參數修改成10,然後彈出第三個參數10,因此它根本不在乎你傳什麼,只要傳夠三個或三個以上參數,它就會alert 10。//第五題//彈出window對象的toString()//基本上不是[object Window] 就是[object],[object DOMWindow]//★★考察動態綁定的用法,詳見我的博文《javascript的動態this與動態綁定》function a() {    alert(this);//這裡將返回其調用者}如果現在直接運行,肯定返回全域對象window。但如果使用apply或call來改變調用對象呢,原則上其第一個參數就是調用對象,通常也被稱之為thisObject。但有幾個特殊情況,當第一參數為null,undefined,或乾脆一個參數也沒有,就會預設為是傳入window對象。

補充實驗:

<br /> var cc = function dd(){<br /> alert("司徒正美!!!")<br /> }</p><p> alert(cc)<br /> alert(dd) //注意IE與標準的區別<br />

運行代碼

嘛,解釋就完全按我的理解去寫啦,應該大體上和Nicholas C. Zakas差不多。可能他的更詳細,畢竟從原文篇幅來看也確實如此,英文好的就看英文吧。本時我搜到一些俄羅斯文,法文什麼的,也基本上貼在google線上翻譯上,連蒙帶猜地學習。外國人的技術比我們強多了,大家應該多上外國網站。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.