JavaScript -- 揮舞函數(shù)

本文中的內(nèi)容來自于 《JavaScript 忍者秘籍》。


函數(shù)存儲(chǔ)

利用以下代碼可以完成函數(shù)存儲(chǔ)功能码倦。

var store = {
    nextId: 1,
    cache: {},
    add: function(fn) {
        if (!fn.id) {
            fn.id = store.nextId++;
            return !!(store.cache[fn.id] = fn);
        }
    }
};

使用場景:可以用來存儲(chǔ)事件的回調(diào)函數(shù)黑竞,由于在 addEventListenerattachEvent 的解綁過程中都需要原樣傳入綁定的函數(shù)僻焚,所以我們可以將綁定的函數(shù)存儲(chǔ)下來,以供解綁事件時(shí)使用汁咏。

自記憶函數(shù)

所謂自記憶函數(shù),就是說函數(shù)自己能夠記住先前計(jì)算的結(jié)果作媚,這樣就能避免相同的計(jì)算執(zhí)行兩次梆暖,可以顯著的提高性能。比如說下面這個(gè)檢測(cè)是否為素?cái)?shù)的函數(shù)掂骏。

    function isPrime(value) {
        if (!isPrime.results) {
            isPrime.results = {};
        }
        if (isPrime.results[value] !== undefined) {
            return isPrime.results[value];
        }
        var prime = value !== 1;
        for(var i = 2; i < value; i++) {
            if (value % i === 0) {
                prime = false;
                break;
            }
        }
        return isPrime.results[value] = prime;
    }

緩存記憶有兩個(gè)優(yōu)點(diǎn):

  1. 在函數(shù)調(diào)用獲取之前計(jì)算結(jié)果的時(shí)候轰驳,最終用戶享有性能優(yōu)勢(shì)。
  2. 發(fā)生在幕后弟灼,完全無縫级解,最終用戶和頁面開發(fā)人員都無需特殊操作或者為此做任何額外的初始化工作。

將緩存記憶用在 DOM 的獲取操作上田绑,可以獲得 5 倍的性能提升勤哗,如下所示。

function getElements(name) {
    if (!getElements.cache) {
        getElements.cache = {};
    }

    return getElements.cache[name] = 
        getElements.cache[name] ||
        document.getElementsByTagName(name); 
}

上面我們求素?cái)?shù)的例子中掩驱,其實(shí)是在函數(shù)中對(duì)結(jié)果進(jìn)行了緩存芒划,不過值得注意的一點(diǎn)是冬竟,這種實(shí)現(xiàn)只有在我們能獲取到函數(shù)體的時(shí)候才可以使用。下面我們就對(duì)上面的函數(shù)進(jìn)行改寫民逼。

Function.prototype.memoized = function(key) {
    this._values = this._values || {};

    return this._values[key] !== undefined ?
        this._values[key] :
        this._values[key] = this.call(this, key);
};

function isPrime(num) {
    var prime = num != 1;

    for(var i = 2; i < num; i++) {
        if (num % i === 0) {
            prime = false;
            break;
        }
    }

    return prime;
}

console.log(isPrime.memoized(5));
console.log(isPrime._values[5]);

這種寫法可以解決剛才我們提出的無法獲取函數(shù)體的問題泵殴,不過又出現(xiàn)了一個(gè)問題,因?yàn)樯厦娴暮瘮?shù)要求調(diào)用者在使用 isPrime() 的時(shí)候必須要跟上 .memoized()拼苍,不過調(diào)用者不可能時(shí)刻都能記得這一點(diǎn)笑诅,所以對(duì)于這個(gè)函數(shù)我們還可以改寫,如下所示:

Function.prototype.memoized = function(key) {
    this._values = this._values || {};

    return this._values[key] !== undefined ?
        this._values[key] :
        this._values[key] = this.call(this, key);
};

Function.prototype.memoize = function(key) {
    var fn = this;
    return function() {
        return fn.memoized.call(fn, key);
    }
};

var isPrime = (function(num) {
    var prime = num !== 1;

    for(var i = 2; i < num; i++) {
        if (num % i === 0) {
            prime = false;
            break;
        }
    }

    return prime;
}).memoize();

console.log(isPrime(5));

不過疮鲫,上面的功能都被添加在 Function 上吆你,由所有函數(shù)實(shí)例共享,如果感覺這么做有所不妥俊犯,可以使用下面這種方式妇多。

function memoize(fn) {
    var cache = {};

    return function(key) {
        console.log("before: " + cache[key]);
        return cache[key] !== undefined ?
            cache[key] :
            cache[key] = fn.call(this, key);
    }
}

只需要對(duì)要緩存的函數(shù)進(jìn)行包裝即可。

函數(shù)判斷

一般而言燕侠,要判斷一個(gè)函數(shù)類型砌梆,只需要利用 typeof functionName 即可(會(huì)返回字符串 function)。不過會(huì)有一些特殊情況讓我們的判斷失效贬循,比如下面幾種:

  1. Opera: 在 HTML<object> 元素上使用 typeof的話咸包,會(huì)返回 function,而不是我們期望的 object杖虾。(書中說在 Firefox 中會(huì)出現(xiàn)這個(gè)問題烂瘫,不過我親自檢測(cè)之后,發(fā)現(xiàn)我電腦上的 Firefox并沒有出現(xiàn)上述問題奇适,反而是 Opera 出現(xiàn)了這個(gè)問題 )坟比。

  2. Safari: Safari 認(rèn)為 DOMNodeList 是一個(gè) function,所以 typeof document.body.childNodes == function嚷往。(本人未親自嘗試)

基于以上情況葛账,我們需要尋找一種完美的解決方案,不過事實(shí)上并不存在完美的解決方案皮仁,倒是有一種接近完美的方案籍琳,那就是利用 Object.toString() 方法。代碼如下:

function isFunction(fn) {
    return Object.prototype.toString.call(fn) === "[object Function]";  
}

利用這項(xiàng)技術(shù)贷祈,還可以判斷 String, RegExp, Date等其它對(duì)象趋急。

這里我們不直接調(diào)用 fn.toString() 的原因有兩個(gè):

  1. 不同的對(duì)象可能有自己的 toString() 方法實(shí)現(xiàn)。

  2. JavaScript 中的大多數(shù)類型都已經(jīng)有一個(gè)預(yù)定義的 toString() 方法覆蓋了 Object.prototype 提供的 toString() 方法势誊。

從下面可以看出 StringArray 重寫了 ObjecttoString() 方法呜达。

var sContent = "Hello World";
console.log(sContent.toString());   // "Hello World"

var aContent = [1, 2, 3];
console.log(aContent.toString());   // "[1, 2, 3]" 

剛才已經(jīng)提及,上面這個(gè)檢測(cè)的方法只是接近完美粟耻,這說明它也有失誤的情況查近,比如在 IE 中會(huì)將 DOM 元素的方法報(bào)告成 object眉踱。

偽造數(shù)組

出于某種目的(我也不知道),我們可以將對(duì)象偽造成一個(gè)數(shù)組霜威,具體操作如下:

var eles = {
    length: 0,
    add: function(ele) {
        Array.prototype.push.call(this, ele);
    }
};

eles 對(duì)象添加了一個(gè) length 屬性谈喳,當(dāng)調(diào)用 push 方法時(shí),length 屬性會(huì)自動(dòng)增加侥祭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茄厘,隨后出現(xiàn)的幾起案子矮冬,更是在濱河造成了極大的恐慌,老刑警劉巖次哈,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胎署,死亡現(xiàn)場離奇詭異,居然都是意外死亡窑滞,警方通過查閱死者的電腦和手機(jī)琼牧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哀卫,“玉大人巨坊,你說我怎么就攤上這事〈烁模” “怎么了趾撵?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長共啃。 經(jīng)常有香客問我占调,道長,這世上最難降的妖魔是什么移剪? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任究珊,我火速辦了婚禮,結(jié)果婚禮上纵苛,老公的妹妹穿的比我還像新娘剿涮。我一直安慰自己,他們只是感情好攻人,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布幔虏。 她就那樣靜靜地躺著,像睡著了一般贝椿。 火紅的嫁衣襯著肌膚如雪想括。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天烙博,我揣著相機(jī)與錄音瑟蜈,去河邊找鬼烟逊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛铺根,可吹牛的內(nèi)容都是我干的宪躯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼位迂,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼访雪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掂林,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤臣缀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泻帮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體精置,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年锣杂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脂倦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡元莫,死狀恐怖赖阻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踱蠢,我是刑警寧澤政供,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站朽基,受9級(jí)特大地震影響布隔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稼虎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一衅檀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霎俩,春花似錦哀军、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柳击,卻和暖如春猿推,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工蹬叭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藕咏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓秽五,卻偏偏與公主長得像孽查,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坦喘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,237評(píng)論 0 4
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品盲再,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式瓣铣。簡單...
    舟漁行舟閱讀 7,765評(píng)論 2 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理答朋,服務(wù)發(fā)現(xiàn),斷路器坯沪,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 一個(gè)古老但又亙古不變的話題绿映,我不知道什么時(shí)候才會(huì)有一個(gè)結(jié)束擒滑,可能存在一個(gè)階段一個(gè)階段的總結(jié)腐晾,在這一路上不斷改變。會(huì)...
    櫻花散盡薔薇盛開閱讀 171評(píng)論 0 0
  • @升本吐槽君 各高等學(xué)校: 普通高等教育屫ひ唬科升本科(以下簡稱專升本)是我省考試招生制度的重要組成部分藻糖,是滿足學(xué)生學(xué)...
    智博周老師閱讀 4,678評(píng)論 0 2