Effective JavaScript讀書筆記(一)

做爲一個前端新人,多讀書讀好書,夯實基礎是十分重要的,正如蓋樓房同樣,底層穩固了,才能越壘越高。從開始學習到如今,基礎的讀了紅寶書《JavaScript高級程序設計》,犀牛書《JavaScript權威指南》,特別是紅寶書,是把我領進js領域的一本書。如今到了進階階段(可能紅寶書還會回去繼續翻),準備開始讀《Effective JavaScript》,剛拿到手,很薄的一本書,也把讀書筆記整理下來,但願養成一個良好的讀書習慣。前端

讓本身習慣JavaScript

瞭解JavaScript的版本

目前主流JavaScript版本任然是ES5,在ES5開始引入嚴格模式正則表達式

use strict;//在文件頭或者函數體頂部使用,就是嚴格模式

通常來講,咱們若是想編寫一個通用型插件,都須要使用嚴格模式來進行開發,可是在使用嚴格模式開發時會出現一個問題,工程前後引入兩個文件file1.js和file2.js,file1.js使用的嚴格模式進行開發,file2是非嚴格模式,那麼下面的代碼會出問題。編程

<script src="file1.js" />
<script src="file2.js" />
// 這麼引入兩個文件,file2也會按照嚴格模式運行,那麼若是file2.js出現了非嚴格模式的行爲,程序就會報錯
所以,在嚴格模式下開發通用插件的時候須要注意這個問題

解決辦法:使用當即執行函數IIFE進行開發。瀏覽器

(function(){
    'use strict';
    function foo(){
        //你的插件內容
    }
})();

理解JavaScript浮點數

JavaScript中只有一種數值類型,不管是整數仍是浮點數,都被表示爲Number類型,可使用typeof關鍵字查看它們。安全

typeof 17.2;//'number'
typeof 26;//'number'

JavaScript之中全部的數字類型都是雙精度浮點數,整數也能夠用雙精度浮點數來表示,如JavaScript之中所能表示的整數範圍是(2e-53~2e53).函數

JavaScript中的浮點數是不精確的

其中最著名的例子就是:0.1+0.2;//0.30000000000000004學習

JavaScript中的數字類型在表示浮點數上不必定精確,使用時要慎重編碼

小心隱式的強制轉換

終於到了JavaScript強大的飲食轉換了,先來看一個簡單的例子spa

(([][[]]+[])[+!![]]+([]+{})[!+[]+!![]]).toUpperCase();

猜猜上面的代碼的結果是什麼?答案是:NB,沒錯,JavaScript就是這麼NB。根本絕不相關的東西,這也正是體現了JavaScript隱式轉換的強大之處,感興趣的能夠百度一下上面爲何會出現這樣的結果。插件

隱式轉換的一些原則

    • 布爾型與數字類型相互轉換
      其中,true對應1,false對應0.

      3+true; // 4
      while(1){ //至關於while(true)
          //無限循環
      }
    • 字符串與數字相互轉換
      在這裏不得不提的就是JavaScript對運算符加號「+」的重載,JavaScript的加號不只能夠進行數字相加,還能夠進行字符串的拼接工做,還能夠進行數字與字符串的隱式轉換工做。例以下面的幾行代碼

      2 + 3; // 5
      "hello" + " world";// "hello world"
      2 + "3"; // "23"
      // 這裏還有個十分重要的,數字字符串以前若是隻存在一個加號,會將字符串隱式轉換成數字類型
      +"3";// 3
      +"3fsdf"; //NaN
      1+(+"3");// 4,必須有括號,不然JavaScript會把兩個加號編程自加運算,從而報錯表達式不合法
      // 須要注意的是,對於加法來講,隱式轉換的優先級字符串高於數字類型,而位運算和乘法除法運算數字類型高於字符串類型
      "17" * 3; // 51
      "8" | "1";// 9
    • 強制轉換的隱藏錯誤

      null會在運算中隱式轉換成0
      一個未被定義的變量(undefined)會被隱式轉換成浮點類型的NaN。
      //關於NaN的幾點注意
      var x = NaN; x === NaN;//false
      isNaN(NaN);// true
      //可是isNaN對於其餘不是浮點類型的數來講,也會隱式轉換成NaN,所以這個API存在問題
      isNaN('string');//true
      isNaN(undefined);//true
      isNaN({});//true
      //所以若是想判斷是否是正正的NaN,咱們能夠寫一個函數來判斷
      function isReallyIsNaN(number) {
          return number !=== number; //利用NaN不等於自身這一特性
      }
    • 對象的隱式轉換
      默認來講,對象也會被隱式轉換成字符串

      "the Math object: "+ Math;//"the Math object: [object Math]",Math對象被隱式轉換爲字符串
      // valueOf方法是真正爲那些表明數值的對象(Number)而設計的
          var obj = {
          toString: function() {
              return '[object Object]';
          },
          valueOf : function() {
              return 26;
          }
      }
      'the obj true value is:'+obj;//'the obj true value is:26',

      對象的valueOf纔是真值

    • 真值運算
      JavaScript中的邏輯運算if、||和&&理論上是能夠接受任何值的,由於JavaScript中
      全部類型都會在邏輯運算中轉換成布爾值

      JavaScript中有7個假值:false、0,-0、""、NaN、null、undefined

      因爲數字和字符串可能爲假值,因此,使用針織運算檢查函數參數或者對象屬性是否已經存在不是絕對安全的。

      function point(x){
          if(!x){
              return 26;//若是x爲假值,不傳或者傳入0,函數都會返回26
          }
      }
      point(0);//x:26
      //可是,傳入0這個值是徹底有可能的,因此這種判斷形勢是不正確的
      function point(x){
          if(typeof x === 'undefined'){
              return 26;
          }
          //或者使用if(x === undefined)來判斷也能夠
      }

    原始類型優於封裝類型

    JavaScript對象擁有六個原始值基本類型: 布爾值,數字,字符串,null,undefined和對象。

    須要注意的是,使用typeof對null判斷獲得的結果是'object',ECMAScript標準描述null是一個獨特的類型

    建立原始類型與建立基本類型

    //建立一個String對象,內部封裝一個字符串值
    var s = new String("hello");
    s + ' world';// 'hello world'
    //建立一個原始類型
    var str = 'string';
    //封裝類型本質是一個對象,原始類型纔是基本類型,可使用typeof來查看
    typeof s;// 'object'
    typeof str;// 'string'
    //因爲封裝類型自身是一個對象,所以即便內部封裝的值相同,兩個對象也是不相等的
    var s1 = new String('string');
    var s2 = new String('string');
    s1 === s2;//false
    s1 == s2;//false

    整體來說,通常不須要使用封裝類型來代替基本類型,由於基本類型不管是從聲明仍是使用都較爲方便。並且,基本類型自己是沒有任何方法的,不過能夠隱式轉換成String對象來執行其內部方法:

    var s = 'hello';//基本類型
    s.toUpperCase();//HELLO,將s隱式轉換成String對象

    【注】隱式封裝的類型有一點須要特別注意:每一次隱式封裝都會產生一個新的String對象,原來的對象會被拋棄,也就是說新產生的隱式封裝對象生命週期就是所在行代碼執行完成。

    'string'.value = 26;
    'string'.value;//undefined
    第二行代碼隱式封裝造成了新的String對象,新的String對象內部沒有value這個屬性值,所以是undefined

    對JavaScript原始類型值設置屬性是沒有意義的

    避免對回合類型使用 == 運算符

    因爲JavaScript隱式轉換的存在,所以,在使用 == 運算符的時候,有時候可能不會獲得咱們所預期的結果。

    '1.0e0' == { valueOf: function(){ return true } };
    //結果是true,由於右側valueOf結果是true,會被隱式轉換成數字1,根據隱式轉換法則,左側字符串也會被隱式轉換成1,所以比較是相等的。
    // 使用==運算符比較時一些特殊狀況
    null == undefined;//true,這種狀況永遠是true
    null/undefined ==
    string/number/boolean;//false,這種狀況永遠是false
    string/number/boolean == string/number/boolean;// 將原始類型轉換爲數字進行比較
    string/number/boolean == Date對象;// 先將原始類型轉化成數字,再將date類型轉化成原始類型(優先嚐試toString,其次嘗試valueOf)
    string/number/boolean == 非Date對象;// 先將原始類型轉化成數字,再將date類型轉化成原始類型(優先嚐試valueOf,其次嘗試toString)

    // 關於Date對象比較問題

    var date = new Date('1993/07/11');
    date == '1993/07/11';//false

    這是由於Date對象調用toString方法以後轉換的不是咱們所熟知的字符串形式。

    在瀏覽器中調用date.toString(),結果是"Sun Jul 11 1993 00:00:00 GMT+0800 (中國標準時間)"

    //將Date類型字符串轉換成咱們定義格式的字符串
    function toYMD(date){
        var y = date.getYear() + 1,
            m = date.getMonth() + 1,
            d = date.getDate();
        return y + '/'
             + (m < 10 ? '0' + m : m) + '/'
             + (d < 10 ? '0' + d : d);
    }
    toYMD(new Date('1993/07/11')); //"1993/07/11"

    在比較的時候,最好使用嚴格相等運算符 ===,這是一個良好的習慣

    瞭解分號插入的侷限

    JavaScript語法對於分號沒有硬性的規定,其語言機制自身會自動添加分號而區分開語句,瞭解分號插入的規則,對於提升JavaScript代碼的嚴謹性有着巨大的幫助。

    分好僅在 } 標記以前、一個或多個換行符以後和程序的輸入結尾被插入

    換而言之,咱們只能夠在一行、一個代碼塊和一段程序結束的地方省略分號,其餘任何地方省略分好都有可能出現錯誤。

    function foo1(r){ r += r; return r };//合法
    function foo2(r){ r += r return r };//不合法

    分好僅在隨後的輸入標記不能被解析時插入

    換句話說,分好是JavaScript爲咱們提供的一種錯誤校訂機制

    a = b
    (f());
    // 上面這段代碼會被解析成
    a = b(f());//這是一條合法語句
    a = b
    f();//下面這段代碼會被解析成兩條獨立的語句,由於 a = b f()是不合法的語句

    換句話說,其實JavaScript只是爲咱們機械化的解決了語法問題而已,若是解析不合法,就會爲咱們經過插入分號來解決問題,可是,可能不是咱們所預期的,所以,規範化的代碼纔是重中之重,儘可能不要省略分號。

    另外一個比較重要的狀況是:return語句,在return關鍵字和其可選參數之間必定不能夠包含換行符。

    return {}; //一條語句,返回一個空對象
    return 
    {}; 
    //上面語句等價於
    return ; 
    {}
    ;
    也就是會自動在return後面的換行符前插入一個分號

    另一種特殊狀況就是++運算符和--運算符

    a
    ++
    b;
    //會被解析成
    a;
    ++b;

    在return、throw、break、continue、++、--的參數以前不能夠換行

    分號不會做爲分隔符在for循環空語句的頭部被自動插入

    也就是說,for循環體內必須顯式的包含分號,不然會出錯

    for(var i = 0, total = 1 // 解析出錯
        i < n
        i++)

    視字符串爲16位的代碼單元序列

    幾種流行的Unicode編碼:utf-八、utf-1六、utf-32

    • JavaScript字符串是由16位代碼單元組成,而不是由Unicode代碼點組成

    • JavaScript使用兩個代碼單元表示2e16及以上的Unicode代碼點。這兩個代碼單元被稱爲代碼對。

    • 代理對甩開了字符串元素計數,length、charAt、charCodeAt方法以及正則表達式模式受到了影響

    相關文章
    相關標籤/搜索