鍍金池/ 教程/ HTML/ 檢測(cè)與構(gòu)建丟失的函數(shù)
備忘錄模式
解釋器模式
類(lèi)似 Python 的 zip 函數(shù)
類(lèi)變量和實(shí)例變量
提示參數(shù)
指數(shù)對(duì)數(shù)運(yùn)算
檢查變量的類(lèi)型是否為數(shù)組
由數(shù)組創(chuàng)建一個(gè)字符串
生成隨機(jī)數(shù)
刪除數(shù)組中的相同元素
大寫(xiě)單詞首字母
雙向服務(wù)器
類(lèi)的混合
計(jì)算復(fù)活節(jié)的日期
轉(zhuǎn)換弧度和度
找到上一個(gè)月(或下一個(gè)月)
雙向客戶(hù)端
橋接模式
嵌入 JavaScript
AJAX
觀察者模式
克隆對(duì)象(深度復(fù)制)
一個(gè)隨機(jī)整數(shù)函數(shù)
清理字符串前后的空白符
歸納數(shù)組
平方根倒數(shù)快速算法
適配器模式
打亂數(shù)組中的元素
將數(shù)組連接
使用數(shù)組來(lái)交換變量
更快的 Fibonacci 算法
服務(wù)器
服務(wù)端和客戶(hù)端的代碼重用
客戶(hù)端
查找子字符串
策略模式
CoffeeScrip 的 type 函數(shù)
由數(shù)組創(chuàng)建一個(gè)對(duì)象詞典
回調(diào)綁定
工廠方法模式
映射數(shù)組
當(dāng)函數(shù)括號(hào)不可選
生成可預(yù)測(cè)的隨機(jī)數(shù)
不使用 jQuery 的 Ajax 請(qǐng)求
把字符串轉(zhuǎn)換為小寫(xiě)形式
類(lèi)方法和實(shí)例方法
擴(kuò)展內(nèi)置對(duì)象
定義數(shù)組范圍
MongoDB
匹配字符串
創(chuàng)建一個(gè)不存在的對(duì)象字面值
列表推導(dǎo)
比較范圍
修飾模式
檢測(cè)每個(gè)元素
拆分字符串
字符串插值
對(duì)象數(shù)組
去抖動(dòng)函數(shù)
使用 Nodeunit 測(cè)試
SQLite
單件模式
篩選數(shù)組
替換子字符串
數(shù)組最大值
計(jì)算(美國(guó)和加拿大的)感恩節(jié)日期
找到一個(gè)月中的最后一天
計(jì)算兩個(gè)日期中間的天數(shù)
基本的 HTTP 服務(wù)器
把字符串轉(zhuǎn)換為大寫(xiě)形式
使用 HTML 命名實(shí)體替換 HTML 標(biāo)簽
For 循環(huán)
模板方法模式
重復(fù)字符串
使用 Jasmine 測(cè)試
對(duì)象的鏈?zhǔn)秸{(diào)用
數(shù)學(xué)常數(shù)
反轉(zhuǎn)數(shù)組
計(jì)算月球的相位
使用 Heregexes
查找子字符串
生成器模式
遞歸函數(shù)
HTTP 客戶(hù)端
創(chuàng)建 jQuery 插件
檢測(cè)與構(gòu)建丟失的函數(shù)
生成唯一ID
命令模式

檢測(cè)與構(gòu)建丟失的函數(shù)

問(wèn)題

你想要檢測(cè)一個(gè)函數(shù)是否存在,如果不存在則構(gòu)建該函數(shù)。(比如 Internet Explorer 8 的 ECMAScript 5 函數(shù))。

解決方案

使用存在賦值運(yùn)算符(?=)來(lái)把函數(shù)分配給類(lèi)庫(kù)的原型(使用 :: 簡(jiǎn)寫(xiě)),然后把它放于一個(gè)立即執(zhí)行函數(shù)表達(dá)式中(do ->)使其含有所有變量。

do -> Array::filter ?= (callback) ->
  element for element in this when callback element

array = [1..10]

array.filter (x) -> x > 5
# => [6,7,8,9,10]

討論

在 JavaScript (同樣地,在 CoffeeScript)中,對(duì)象都有一個(gè)原型成員,它定義了什么成員函數(shù)能夠適用于基于該原型的所有對(duì)象。
在CoffeeScript中,你可以使用 :: 捷徑來(lái)訪問(wèn)這個(gè)原型。所以如果你想要把過(guò)濾函數(shù)添加至數(shù)組類(lèi)中,就執(zhí)行 Array::filter = ... 語(yǔ)句。它能把過(guò)濾函數(shù)加至所有數(shù)組中。

但是,不要去覆蓋一個(gè)在第一時(shí)間還沒(méi)有構(gòu)造的原型。比如,如果 Array::filter = ... 已經(jīng)以快速本地形式存在于瀏覽器中,或者庫(kù)制造者擁有其對(duì)于 Array::filter = ... 的獨(dú)特版本,這樣以來(lái),你要么換一個(gè)慢速的 JavaScript 版本,要么打破這種依賴(lài)于其自身 Array::shuffle 的庫(kù)。
你需要做的僅僅是在函數(shù)不存在的時(shí)候添加該函數(shù)。這就是存在賦值運(yùn)算符(?=)的意義。如果我們執(zhí)行 Array::filter = ... 語(yǔ)句,它會(huì)首先判斷 Array::filter 是否已經(jīng)存在。如果存在的話(huà),它就會(huì)使用現(xiàn)在的版本。否則,它會(huì)添加你的版本。

最后,由于存在的賦值運(yùn)算符在編譯時(shí)會(huì)創(chuàng)建一些變量,我們會(huì)通過(guò)把它們封裝在立即調(diào)用函數(shù)表達(dá)式( IIFE )中來(lái)簡(jiǎn)化代碼。這將隱藏那些內(nèi)部專(zhuān)用的變量,以防止泄露。所以假如我們寫(xiě)的函數(shù)已經(jīng)存在,那么它將運(yùn)行,基本上什么都沒(méi)做然后退出,絕對(duì)不會(huì)對(duì)你的代碼造成影響。但是假如我們寫(xiě)的函數(shù)并不存在,那么我們發(fā)送出去的僅是一個(gè)作為閉包的函數(shù)。所以只有你寫(xiě)的函數(shù)能夠?qū)Υa產(chǎn)生影響。無(wú)論哪種方式,?= 的內(nèi)部運(yùn)行都會(huì)被隱藏。

舉例

接下來(lái),我們用上述的方法編譯了 CoffeeScript 并附加了說(shuō)明:

// (function(){ ... })() 是一個(gè) IIFE, 使用 `do ->` 來(lái)編譯它。
(function() {

  // 它來(lái)自 `?=`  運(yùn)算符,用來(lái)檢查 Array.prototype.filter (`Array::filter`) 是否存在。
  // 如果確實(shí)存在,我們把它設(shè)置給其自身,并返回。如果不存在,則把它設(shè)置給函數(shù),并返回函數(shù)。
  // The IIFE is only used to hide _base and _ref from the outside world.
  var _base, _ref;
  return (_ref = (_base = Array.prototype).filter) != null ? _ref : _base.filter = function(callback) {

    // `element for element in this when callback element`
    var element, _i, _len, _results;
    _results = [];
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      element = this[_i];
      if (callback(element)) {
        _results.push(element);
      }
    }
    return _results;

  };
// The end of the IIFE from `do ->`
})();