javascript --- Function模式

来源:http://www.cnblogs.com/beyond-succeed/archive/2016/09/14/5872937.html
-Advertisement-
Play Games

回調函數 在javascript中,當一個函數A作為另外一個函數B的其中一個參數時,則稱A函數為回調函數,即A可以在函數B的運行周期內執行(開始,中間,結束)。 舉例來說,有一個函數用於生成node. 又有一個findNodes函數聲明用於查找所有節點,然後通過callback回調進行執行代碼。 關 ...


回調函數

在javascript中,當一個函數A作為另外一個函數B的其中一個參數時,則稱A函數為回調函數,即A可以在函數B的運行周期內執行(開始,中間,結束)。

舉例來說,有一個函數用於生成node.

var complexComutation = function(){
    // 內部處理,並返回一個node
}

又有一個findNodes函數聲明用於查找所有節點,然後通過callback回調進行執行代碼。

var findNodes = function(callback){
    var nodes = [];
    var node = complexComputation();
    // 如果回調函數可用,則執行她
    if(typeof callback === 'function'){
        callback(node);
    }  
    nodes.push(node);
    return nodes;
}

關於callback的定義,我們可以事先定義好來用:

// 定義callback
var hide = function(node){
    node.style.display = 'node';
}
var hiddenNodes = findNodes(hide);

也可以在調用的時候使用匿名定義,如下:

// 使用匿名定義callback
var blockNodes = findNodes(function(node){
     node.style.display = 'block';
})

我們平時用的最多的,估計就數jQuery的ajax方法的調用了,通過在done/faild上定義callback,以便在ajax調用成功或者失敗的時候做進一步處理,代碼如下(本代碼基於jquery1.8版):

var menId = $('ul.nav').first().attr('id');
var request = $.ajax({
    url: 'script.php',
    type: 'post',
    data: {id: menuId},
    dataType: 'html'
})
// 調用成功時的回調處理
request.done(function(msg){
    $('#log').html(msg);
})
// 調用失敗時的回調處理
request.fail(function(jqXHR, textStatus){
    alert('Request failed:' + textStatus);
});

 

配置對象

如果一個函數(或方法)的參數只有一個,並且參數為對象字面量,我們則稱這種模式為配置對象模式。如下所述:

var her = {
    username: 'gaohan',
    first: 'gao',
    last: 'han'
};
addPerson(her);

則在addPerson函數內部,就可以隨意使用her對象內的值了,一般用於初始化工作,例如jquery里的ajaxSetup也就是這種方式來實現的:

// 事先設置好初始值
$.ajaxSetup({
    url: '/xmlhttp/',
    global: false,
    type: 'POST'
})
// 然後再調用
$.ajax({ data:myData });

另外,很多jquery的插件也有這種形式的傳參,只不過也可以不傳,不傳的時候則就使用預設值了。

返回函數

返回函數,則是指一個函數的返回值為另一個函數,或者根據特定的條件靈活創建的新函數,示例如下:

var setup = function(){
    console.log(1);
    return function(){
        console.log(2);
    };
};
// 調用setup函數
var her = setup(); // 1
her(); // 2
// 或者直接調用也可以;
setup()(); // 2

或者我們可以利用閉包的特性,在函數中加入一個計數器,用來計算函數被調用的次數:

var setup = function(){
    var count = 0;
    return function(){
        retunr ++count;
    };
};
var next = serup();
next(); // 1
next(); // 2
next(); // 3

 

Currying

Currying是函數式編程的一個特性,將多個參數的處理轉化成單個參數的處理,類似鏈式調用。

下麵來舉一個簡單的例子:

function add(x, y){
    var oldx = x, oldy = y;
    if(typeof oldy === 'undefined'){
        return function (newy){
             return oldx + newy;
        }
    } 
    return x + y ;
}

這樣的話,調用方式就有很多種了,比如:

// 測試
typeof add(5); // 'function'
add(3)(4); // 7
// 也可以這樣調用
var add2000 = add(2000);
add2000(10); // 2010

接下來我們定義一個,比較常用的currying函數:

// 第一個參數為要應用的function, 第二個參數是需要傳入的最少參數個數
function curry(func, minArgs) {
    if(minArgs == undefined) {
         minArgs = 1;
    }
    function funcWithArgsFrozen(frozenargs){
         return function () {
              // 優化處理,如果調用時沒有參數,返回該函數本身
              var ages = Array.prototype.slice.call(arguments);
              var newArgs = frozenargs.concat(args);
              if(newArgs.length >= minArgs) {
                   return func.apply(this, newArgs);
              }else{
                   return funcWithArgsFrozen(newArgs);
              }
         }
    }
    return funcWithArgsFrozen([]);
}

這樣,我們就可以隨意定義我們的業務行為了,比如定義加法:

var plus = curry(function(){
    var result = 0;
    for(var i=0; i<arguments.length; ++i){
        result += arguments[i];
    }
    return result;
}, 2)

使用方法多種多樣。

plus(3, 2) // 正常調用
plus(3) // 偏應用
plus(3) (2) // 完整應用(返回5)
plus() (3) () () (2) // 返回5
plus(3, 2, 4, 5) // 可以接受多個參數
plus(3) (2, 3, 5) // 同理

JavaScript里的Function有很多特殊的功效,可以利用閉包以及arguments參數特性實現很多不同的技巧,下一篇我們將繼續介紹利用Function進行初始化的技巧。

立即執行的函數

// 聲明完函數以後,立即執行該函數
(function (){
     console.log('watch out');
}());
// 這種方式聲明的函數,也可以立即執行
!function(){
    console.log('watch out!');
}();
// 如下的方式也都可以哦
~function(){ /* do someing*/ }();
-function(){ /* do someing*/ }();
+function(){ /* do someing*/ }();

 

 立即執行的對象初始化

該模式的意思是指在聲明一個對象(並非函數)的時候、立即執行對象里的某一個方法進行初始化工作,通常該模式可以用在執行一次性的代碼上:

({
    // 這裡你可以定義常量,並設置其它值
    maxwidth:  600,
    maxheight: 400,
    // 當然也可以定義方法
    gimmMax: function(){
        return this.maxwidth + 'x' + this.maxheight;
    },
    init: function(){
        console.log(this.gimmeMax());
        // 更多代碼......
    }
}).init(); // 這樣就能初始化嘍

 

分支初始化

分支初始化是指在初始化的時候,根據不同的條件(場景)初始化不同的代碼,也就是所謂的條件語句賦值。之前我們在處理的時候,常常使用類似下麵的代碼:

var utils = {
    addListener: function(el, type, fn){
        if(typeof window.addEventListener === 'function'){
             el.addEventListener(type, fn, false);
        }else if(typeof document.attachEvent !== 'undefined'){
             el.attachEvent('on' + type, fn); 
        }else{
             el['on' + type] = fn;
        }
    },
    removeListener: function(el, type, fn){
        // 神馬之類的......
    }
}

我們來改進一下,首先我們要定義兩個介面,一個用來add事件句柄,一個用來remove事件句柄,代碼如下:

var utils = {
    addListener: null,
    removeListener: null
};

實現代碼如下:

if (typeof window.addEventListener === 'function') {
    utils.addListener = function (el, type, fn) {
        el.addEventListener(type, fn, false);
    };
} else if (typeof document.attachEvent !== 'undefined') { // IE
    utils.addListener = function (el, type, fn) {
        el.attachEvent('on' + type, fn);
    };
    utils.removeListener = function (el, type, fn) {
        el.detachEvent('on' + type, fn);
    };
} else { // 其它舊瀏覽器
    utils.addListener = function (el, type, fn) {
        el['on' + type] = fn;
    };
    utils.removeListener = function (el, type, fn) {
        el['on' + type] = null;
    };
}

用起來,是不是就很方便了?代碼也優雅多了。

自聲明函數

一般是在函數內部,重寫重名函數代碼,比如:

var her = function(){
    alert('Boo!');
    her = function(){
        alert('Double Boo!!');
    }
}

這種代碼,非常容易使人迷惑,我們先來看看例子的執行結果:

// 1.添加新屬性
scareMe.prototype = 'Anna';
// 2. scareMe賦予一個新值
var prank = scareMe;
// 3. 作為一個方法調用
var spooky = {
    boo: scareMe
}
// 使用新變數名稱進行調用
prank(); // 'Boo!'
prank(); // 'Boo!'
console.log(spooky.boo.property); // 'properly'

通過執行結果,可以發現,將定於的函數賦值與新變數(或內部方法),代碼並不執行重載的scareMe代碼,而如下例子則正好相反:

// 使用自聲明函數
scareMe(); // Double boo!
scareMe(); // Double boo!
console.log(scareMe.property); // undefined

大家使用這種模式時,一定要非常小心才行,否則實際結果很可能和你期望的結果不一樣,當然你也可以利用這個特殊做一些特殊的操作。

記憶體優化

該模式主要是利用函數的屬性特性來避免大量的重覆計算。通常代碼形式如下:

var myFunc = function (param) {
    if (!myFunc.cache[param]) {
        var result = {};
        // ... 複雜操作 ...
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};

// cache 存儲
myFunc.cache = {};

 

但是上述代碼有個問題,如果傳入的參數是toString或者其它類似Object擁有的一些公用方法的話,就會出現問題,這時候就需要使用傳說中的hasOwnProperty方法了,代碼如下:

var myFunc = function (param) {
    if (!myFunc.cache.hasOwnProperty(param)) {
        var result = {};
        // ... 複雜操作 ...
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};

// cache 存儲
myFunc.cache = {};

或者如果你傳入的參數是多個的話,可以將這些參數通過JSON的stringify方法生產一個cachekey值進行存儲,代碼如下:

var myFunc = function () {
    var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
        result;
    if (!myFunc.cache[cachekey]) {
        result = {};
        // ... 複雜操作 ...
        myFunc.cache[cachekey] = result;
    }
    return myFunc.cache[cachekey];
};

// cache 存儲
myFunc.cache = {};

或者多個參數的話,也可以利用arguments.callee特性:

var myFunc = function (param) {
    var f = arguments.callee,
        result;
    if (!f.cache[param]) {
        result = {};
        // ... 複雜操作 ...
        f.cache[param] = result;
    }
    return f.cache[param];
};

// cache 存儲
myFunc.cache = {};
總結

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、DOM:文檔對象模型,Document Object Model; 2、BOM:瀏覽器對象模型,Browser Object Model; 3、DOM組成:核心DOM,XML DOM,HTML DOM; 4、節點樹: ①document node:文檔節點,document為根節點;②eleme ...
  • 有序列表 無序列表 定義列表 定義列表由 定義條件(definition term) 和 定義描述(definition description) 構成 ``標記後面添加要解釋的名詞 ``標記後面添加名詞的具體解釋 慄子: 輸出效果: ...
  • 標題 `` 對齊方式有left,center,right三種,預設表示left 段落 段落標記的結束標記''可以省略,一個新的段落開始標記就意味著上一個段落的結束 換行 不換行 當一段很長的時候,瀏覽器一般會自動進行換行處理,如果不希望瀏覽器這麼做,可以使用``標記 水平線 使用``可以在網頁中插入 ...
  • [1]刪除節點 [2]插入節點 [3]特性節點 [4]文本節點 ...
  • 這次和大家分享的是自己寫的一個table常用幾種展示格式的js插件取名為(table-shenniu),樣式使用的是bootstrap.min.css,還需要引用jquery.min.js包,這個插件由來的目的是項目中需要一個table格式的提交數據的頁面,功能有合併單元格,只能提交選中行數據,全選 ...
  • JavaScript的函數定義有個特點,它會先掃描整個函數體的語句,把所有申明的變數“提升”到函數頂部: 雖然是strict模式,但語句var x = 'Hello, ' + y;並不報錯,原因是變數y在稍後申明瞭。但是alert顯示Hello, undefined,說明變數y的值為undefine ...
  • screen.width screen.height screen.availHeight //獲取去除狀態欄後的屏幕高度 screen.availWidth //獲取去除狀態欄後的屏幕高度 一、通過瀏覽器獲得屏幕的尺寸 二、獲取瀏覽器視窗內容的尺寸 //高度 window.innerHeight ...
  • 簡單說明 這篇文章是我學習react一個多月來的總結,從基礎開始(包括編輯器設置,構建工具搭建),一步一步走向react開發。相信我,看完這篇文章,跟著文章的步驟走,保證讓你入門react並愛上react,掌握react-router,redux。本文遵循由淺入深的原則。 一、編輯器開始 這裡介紹的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...