《JavaScript設計模式與開發實踐》讀書筆記之基礎部分

zimplexing發表於2017-09-18

幾個名詞

  • 鴨子模型:通俗的講就是如果它走起來像鴨子,叫起來像鴨子,那麼它就是鴨子。

    鴨子模型主要是指導我們只關注物件的行為,而不是關注物件本身

  • 多型:同一操作作用於不同物件上面,可以產生不同的解釋和不同的執行結果。換句話說,給不同的物件傳送不同的訊息,這些物件會根據這個訊息分別給出不同的反饋

    多型背後的思想是將“做什麼”和“誰去做以及怎樣去做”分離開來,也就是將“不變的事物”與“可能改變的事物”分離開來

老生常談之this,apply,call

this指向

普通的方法定義之後,方法中的this指向,是取決於方法執行的環境動態繫結的,而非方法被宣告時的環境。在es6中,使用箭頭函式,可以將this固定下來,this永遠指向的箭頭函式宣告時的this的指向。但是箭頭函式不能作為建構函式使用,不能使用arguments物件

  • 作為物件的方法呼叫

  • 作為普通函式呼叫

    var obj = {
      name: 'javascript',
      getName: function(){
        return this.name
      }
    }
    obj.getName() // javascript 作為物件的方法進行呼叫,指向該物件
    var getName = obj.getName
    getName() // undefined 
              // 將物件的方法重新複製給新的變數,
              // 然後執行,getName作為普通函式呼叫,指向全域性的name複製程式碼
    <html>
      <body>
        <div id="div1">
          我是一個div
        </div>
      </body>
      <script>
          window.id = 'window';
    
        document.getElementIdById('div1').onclick = function(){
          alert(this.id) // div1
          var callback = function(){
            alert(this.id)
          }
          callback() // window 作為普通方法進行呼叫,指向this全域性的window物件
        }
      </script>
    </html>複製程式碼

  • 構造器呼叫

    使用new關鍵字生成一個物件,並將其建構函式的this都指向這個生成的物件

  • Function.prototype.call和Function.prototype.apply呼叫

    動態改變this的指向

“高逼格”的call,apply

callapplay的幾個用法和場景

  1. 改變this的指向

    var obj1 = {
      name: 'obj1'
    }
    
    var obj2 = {
      name: 'obj2',
      getName: function(){
        return this.name
      }
    }
    
    obj2.getName() // obj2
    obj2.getName.apply(obj1) // obj1複製程式碼

  2. 對不支援bind的低版本瀏覽器提供相容方式

    Function.prototype.bind(content){
      var _self = this;
      return function(){
        _self.apply(content,arguments)
      }
    }複製程式碼

  3. 借用其他物件的方法

    最常用的就是arguments借用Array的方法

    (function(){
      Array.ptototype.push(arguments,4)
      console.log(arguments) // [1,2,3,4]
    })(1,2,3)複製程式碼

又是閉包,還有高階函式

通俗易懂的閉包

沒搞懂閉包肯定是因為沒太理解js的變數宣告週期。

  • 全域性變數:變數的生命週期一直存在,不會被銷燬,除非我們主動去銷燬該變數
  • 區域性變數:區域性變數一般存在在函式體內(es6有塊級作用域),當區域性變數的函式執行直接之後,該變數也就被銷燬了。

但是區域性變數存在一種情況,在函式執行完之後不會被銷燬,那就是該區域性變數還存在著引用(其他地方還在用這個變數),此時就出現了閉包。該區域性變數有留下來的理由了,所以也就延續下來了。

說到閉包,必會說到閉包的缺點——造成記憶體洩漏,當然這個記憶體洩漏時在使用閉包不當的時候才會出現這個問題,這個問題在本書的3.1.6章節中,作做了比較詳細的解釋(作者漂亮的甩了“一波鍋”)。有興趣的可以自己翻閱。

舉一個簡單的閉包的例子

function count(){
  var a = 0;
  return function(){
    return a++;
  }
}
var conutNum = count()
conutNum() // 0
conutNum() // 1
conutNum() // 2複製程式碼

沒那麼神祕的高階函式

滿足了一下條件之一的就是高階函式:

  1. 函式可以作為引數被傳遞
  2. 函式可以作為返回值輸出
  • 函式作為引數被傳遞

    平時使用的回撥函式都算。

    再舉個例子:

    // 從小到大排序
    [1,3,2,5,4].sort(function(a,b){
      return a-b
    })
    
    // 從大到小排序
    [1,3,2,5,4].sort(function(a,b){
      return b-a
    })複製程式碼
  • 函式作為返回值輸出

    大部分的閉包都算。

    再舉個單例模式的例子:

    var getSingle = function(fn){
      var ret;
      return function(){
        return ret || ret = fn.apply(this,arguments)
      }
    }
    
    var createScript = getSingle(function(){
      document.createElemet('script')
    })
    
    var script1 = createScript()
    var script2 = createScript()
    script1 === script2 // true複製程式碼

高階函式的其他的一些應用

  1. 函式柯里化(function currying)

    函式柯里化又稱部分求值,一個柯里化的函式首先會接受一些引數,接受了這些引數之後,該函式並不會立即求值,而是繼續返回另外一個函式,剛才傳入的引數在函式形成的閉包中被儲存起來。待到函式被真正需要求值的時候,之前傳入的所有引數都會被一次性用於求值

  2. 函式反柯里化(uncurrying)

  3. 函式節流

    函式被頻繁呼叫(resizemousemove等事件),影響效能時,需要人為的限制函式的執行頻率,這種函式一般被稱為throttle函式

    var throttle = function(fn, interval){
      var _self = fn,
          timer,
          firstTime = true;
    
      return function(){
        var args = arguments,
            _me = this;
    
        if(firstTime){
          _self.apply(_me, args);
          retutn firstTime = false;
        }
    
        if(timer){
          return false
        }
    
        timer = setTimeout(function(){
          clearTimeout(timer)
          timer = null
          _self.apply(_me, args)
        }, interval || 500)
      }
    }
    
    window.resize = throttle(function(){
      console.log(1);
    }, 1000)複製程式碼
  4. 分時函式

    用於解決短時間內向內面插入大量的DOM節點,導致頁面渲染卡頓、假死的問題。

    /**
     * @params ary 用於渲染dom節點的資料
     * @parmas fn 渲染dom節點的業務邏輯
     * @params count 一次渲染dom節點的數量
     */
    var timeChunk = function(ary, fn, count){
      var obj,
          t;
    
      var start = function(){
        for(var i = 0; i<Matn.min(count || 1, ary.length); i++){
          var obj = ary.shift();
          fn(obj)
        }
      }
    
      return function(){
        t = setInterval(function(){
          if(ary.length === 0){
            return clearInterval(t)
          }
          start()
        }, 200)
      }
    }複製程式碼
  5. 惰性載入函式

    在函式執行時,需要通過if語句判斷函式的執行分支,為提高效率,可以使用惰性載入函式

文章連線

相關文章