細數 javascript 容易被忽略的文法陷阱

來源:互聯網
上載者:User

JavaScript 可算是世界上最流行的程式設計語言,它曾被 Web 開發設計師貼上噩夢的標籤, 雖然真正的噩夢其實是 DOM API,這個被大量的開發與設計師隨手拈來增強他們的 Web 前端的指令碼語言, 如今越來越被重視,雖則如此,JavaScript 仍然擁有很多讓人費解的東西。

## 1. 它以 Java 命名,但並不是 Java

它最初叫 Mocha, 接著改名為 LiveScript,最後才確定命名為 JavaScript, 根據記錄,Java 的命名與 Netscape 和 Sun 之間的合作有關, 作為交換條件,Netscape 在他們備受歡迎的瀏覽器中建立了 Java 運行時。

值得一提的是,這個名字的出台幾近一個玩笑, 要知道,LiveScript 和 Java 在用戶端指令碼方面存在敵對關係。

不管怎麼說,人們後來不得不一再澄清的一件事就是,JavaScript 和 Java 毫無關係。

PS:我最喜歡的回答是:java和javascript就是“雷鋒和雷鋒塔的關係”。

2. Null 是個對象?

看看這段代碼,它返回的是 object。

console.log(typeof null); // object    

這實在令人費解,假如 null 表示空值,它怎麼可以是對象? 簡單說,它是 JavaScript 最初版本的錯誤,這個錯誤甚至被微軟的 JScript 直接借用。

3. NaN !== NaN

NaN,表示一個非數位值,然而問題是,NaN不等於任何東西,甚至不等於它自己。

console.log(NaN === NaN); // false    

這顯然不對,事實上,如果要判斷一個值確實是 NaN,你需要用 isNaN() 函數。

4. 全域變數

對全域變數的依賴一直被視為 JavaScript 最壞的部分(ECMA 的 JavaScript 5 已經去掉了全域變數, 請參閱 ECMA 推出 JavaScript 5 - 譯者注)。

對簡單的頁面,這無所謂,但複雜的頁面,如果包含大量 JavaScript 指令碼, 你很難知道某個全域變數是在哪裡聲明的,如果幾個全域變數不小心重名,就會引發錯誤。

5. 那些統統被探測為 Mozilla User-Agent 的瀏覽器

必須承認,事實上,這不是 JavaScript  的錯,是各個瀏覽器有意為之。

比如,以下是用 JavaScript 探測 Safari 時得到的結果:

console.log(navigator.userAgent);     // Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10    

是否注意到其中的第一個單詞 Mozilla/5.0,為什麼 Safari 會被探測為 Mozilla, 儘管 Safari 後來已經糾正這一問題,但仍然不能解釋為什麼它們要這樣誤導開發人員。

事實上,你會發現,絕大多數瀏覽器把他們的 User Agent 設定為 Mozilla, 答案要回到10年前,這更多是一種策略。

User Agent 是一段用來標識當前瀏覽器身份的字串,世界上第一個瀏覽器 Mosaic, 曾這樣標誌自己:

Mosaic/0.9     // browser name / version number   

這很合理,因此當 Netscape 出來的時候,它保留了 Mosaic 這個傳統, 還在後面添加了一個加密方式部分。

Mozilla/2.02 [en] (Win95; I)     // browser name / version / encryption   

到目前為止,一切安好,直到 IE3 發布,當 IE3 發布的時候,Netscape 正如日中天, 那時,很多伺服器和程式已經部署了用戶端探測機制,以便認出 Netscape, 雖然現在看來,這很值得爭議,但當時並沒什麼。

當 IE 初次推出它們的 User Agent 標誌的時候,是這個樣子:

MSIE/3.0 (Win95; U)    

這讓 IE 很被動,因為 Netscape 已經能被很多伺服器識別, 因此,開發人員們乾脆希望 IE 被誤認為 Mozilla, 然後,再單獨加一個 IE 的標籤。

Mozilla/2.0 (compatible; MSIE 3.0; Windows 95)    

如今,幾乎所有瀏覽器都步 IE 後塵,將自己標識為 Mozilla,這大概是一種連鎖反應。

6. 不一致的函數範圍

參看以下代碼:

function that will call a function with the name equal to parameter fn.     function foo(fn) {         if (typeof fn === "function") {             fn();         }     }     // Create an object with a property and a method.     var bar = {          barbar : "Hello, World!",          method  : function() {              alert(this.barbar);          }      };      bar.method(); // Alerts Hello, World!      foo(bar.method); // If we call the foo function add pass the "bar.method" method, it somehow alerts "undefined."      foo(function() { bar.method(); }); // alerts Hello, World, after    

foo(bar.method) 返回結果不同原因是,method 函數是被當作 windows 對象, 而不是 bar 下的對象調用的。

要解決這個問題,我們必須從傳遞的匿名函數中調用 bar.method() 。

7. 位操作符

JavaScript 和 Java 有不少共同之處,如位操作。

  • & - and
  • | - or
  • ^ - xor
  • ~ - not
  • >> - signed right shift
  • >>> - unsigned right shift
  • << - left shift

看看第一個 & 操作符,使用 && 應該更有效,因為 JavaScript 和 Java 不一樣,JavaScript 沒有整數,需要來迴轉換,因此,轉換操作花的時間更長。

8. 太多的空實值型別

諸如 null, false, undefined 一類的值幾乎表示同樣的意思,它們之間的不同又讓人很迷惑。

9. 算術問題

雖然 JavaScript 包含很多算術操作,但你不妨運行一下下面的算式,".2+.4" 應該等於 ".6" 是不是,然而返回的確是 "0.6000000000000001"。

JavaScript 在小數計算訪問存在一些小問題。

console.log(.2 + .4); // 0.6000000000000001    

為什麼會這樣?

簡單說,因為 JavaScript 使用 IEEE 標準進行二進位浮點運算, 不過,對整數計算是沒問題的。

  1. 莫名其妙的代碼錯誤

看看以下兩段代碼:

// braces on the right     return {      foo : bar     };     // braces on their own line     return    {       foo : bar      };    

它們應該是一樣的,只是 { 位置不同而已,是吧。

然而我們再看下面的代碼:

var foo = function() {           return {             a : 'b'        };     }();     alert(foo.a); // b     

如果我們把其中的

return  {         a : 'b'    };    

換成

return    {         a : 'b'    };     

就會引發錯誤,這是因為 JavaScript 有一個功能, 會糾正它認為錯誤的代碼書寫,它會自作聰明地在 return 這個詞後面插入一個 ";" , 錯誤因此而生。

return; // JS incorrectly adds this semicolon.     {         a : 'b'; // It'll add a semicolon here as well, because it doesn't realize that this is an object.     };    
附:
  1.  parseInt('06') -> 6    parseInt('07') -> 7    parseInt('08') -> 0    parseInt('09') -> 0    parseInt('10') -> 10  

這是很多語言都會有的問題,就是0開始的數字都是八進位。

  1.  ''        ==   '0'           //false    0         ==   ''            //true    0         ==   '0'           //true    false     ==   'false'       //false    false     ==   '0'           //true    false     ==   undefined     //false    false     ==   null          //false    null      ==   undefined     //true    " \t\r\n" ==   0             //true  
  2.  2 == [2]    // Even stranger    2 == [[[2]]]    // And down-right nutty    var a = { "abc" : 1 };    a[[[["abc"]]]] === a["abc"]; // this is also true  

歸根結底,原因還是一樣——javascript是若類型語言。

  1. var a = {};
    a.b === undefined; // true because property b is not set
    undefined = 42;
    a.b === undefined; // false

    var a = {};
    typeof a.b == "undefined"; // always true

在javascript中,你可以改變undefined的值。

  1. 最不可思議,但又合乎道理的。

     alert(111111111111111111111)     // 輸出111111111111111110000  

其實這不能怪javascript,只能怪IEEE。

既然提到了IEEE,那再來一個。

很奇怪的是,這個本該輸出1或1.0的式子,輸出的居然是0.9999999999999999

  1.  typeof null // object    null === Object // false   1. 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1  

由於部落格空間在國外,所以有時會造成不穩定(你懂滴),如果您覺得我的博文對您有協助,    可以點擊下面按鈕訂閱到郵箱,本站所有文章均已全文輸出。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.