首頁 web前端 js教程 javascript函數的五個運用技巧介紹

javascript函數的五個運用技巧介紹

Nov 17, 2018 pm 03:35 PM
javascript 前端

這篇文章帶給大家的內容是關於javascript函數的五個運用技巧介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

函數對任何一門語言來說都是一個核心的概念,在javascript中更是如此。本文將介紹函數的5個進階技巧

作用域安全的建構子

#建構子其實就是一個使用new運算子呼叫的函式

function Person(name,age,job){
    this.name=name;    
    this.age=age;    
    this.job=job;
}
var person=new Person('match',28,'Software Engineer');
console.log(person.name);//match
登入後複製

如果沒有使用new運算符,原本針對Person物件的三個屬性被加入到window物件

function Person(name,age,job){
    this.name=name;    
    this.age=age;    
    this.job=job;
}          
var person=Person('match',28,'Software Engineer');
console.log(person);//undefinedconsole.log(window.name);//match
登入後複製

window的name屬性是用來標識連結目標和框架的,這裡對該屬性的偶然覆蓋可能會導致頁面上的其它錯誤,這個問題的解決方法就是創建一個作用域安全的建構子

function Person(name,age,job){
    if(this instanceof Person){
            this.name=name;        
            this.age=age;        
            this.job=job;
    }else{
            return new Person(name,age,job);
    }
}var person=Person('match',28,'Software Engineer');
console.log(window.name); // ""console.log(person.name); //'match'var person= new Person('match',28,'Software Engineer');
console.log(window.name); // ""console.log(person.name); //'match'
登入後複製

但是,對建構函式竊取模式的繼承,會帶來副作用。這是因為,在下列程式碼中,this物件並非Polygon物件實例,所以建構子Polygon()會建立並傳回一個新的實例

function Polygon(sides){
    if(this instanceof Polygon){
            this.sides=sides;        
            this.getArea=function(){
                        return 0;
        }
    }else{
            return new Polygon(sides);
    }
}
function  Rectangle(wifth,height){
    Polygon.call(this,2);    
    this.width=this.width;    
    this.height=height;    
    this.getArea=function(){        
    return this.width * this.height;
    };
}
var rect= new Rectangle(5,10);
console.log(rect.sides); //undefined
登入後複製

如果要使用作用域安全的建構函式竊取模式的話,需要結合原型鏈繼承,重寫Rectangle的prototype屬性,使它的實例也變成Polygon的實例

function Polygon(sides){
    if(this instanceof Polygon){
            this.sides=sides;        
            this.getArea=function(){
                        return 0;
        }
    }else{
            return new Polygon(sides);
    }
}
function  Rectangle(wifth,height){
    Polygon.call(this,2);    
    this.width=this.width;    
    this.height=height;    
    this.getArea=function(){
            return this.width * this.height;
    };
}
Rectangle.prototype= new Polygon();var rect= new Rectangle(5,10);
console.log(rect.sides); //2
登入後複製

惰性載入函數

因為各瀏覽器之間的行為的差異,我們經常在函數中包含了大量的if語句,以檢查瀏覽器特性,解決不同瀏覽器的兼容問題。例如,我們最常見的為dom節點新增事件的函數

function addEvent(type, element, fun) {
    if (element.addEventListener) {
        element.addEventListener(type, fun, false);
    }    
    else if(element.attachEvent){
        element.attachEvent('on' + type, fun);
    }    else{
        element['on' + type] = fun;
    }
}
登入後複製

每次呼叫addEvent函數的時候,它都要對瀏覽器所支援的能力進行檢查,首先檢查是否支援addEventListener方法,如果不支持,再檢查是否支持attachEvent方法,如果還不支持,就用dom0級的方法添加事件。這個過程,在addEvent函數每次呼叫的時候都要走一遍,其實,如果瀏覽器支援其中的一種方法,那麼他就會一直支援了,就沒有必要再進行其他分支的偵測了。也就是說,if語句不必每次都執行,程式碼可以運行的更快一些。

  解決方案就是惰性載入。所謂惰性載入,指函數執行的分支只會發生一次,有兩種實現惰性載入的方式

  1、第一種是在函數被呼叫時,再處理函數。函數在第一次呼叫時,函數會被覆寫為另一個以適當方式執行的函數,這樣任何對原函數的呼叫都不用再經過執行的分支了

  我們可以用下面的方式使用惰性載入重寫addEvent()

function addEvent(type, element, fun) {
    if (element.addEventListener) {
        addEvent = function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    }    
    else if(element.attachEvent){
        addEvent = function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    }    
    else{
        addEvent = function (type, element, fun) {
            element['on' + type] = fun;
        }
    }    
    return addEvent(type, element, fun);
}
登入後複製

在這個惰性載入的addEvent()中,if語句的每個分支都會為addEvent變數賦值,有效覆寫了原函數。最後一步便是呼叫了新賦函數。下次呼叫addEvent()時,就會直接呼叫新賦值的函數,這樣就不用再執行if語句了

  但是,這種方法有個缺點,如果函數名稱有所改變,修改起來比較麻煩

  2、第二種是宣告函數時就指定適當的函數。這樣在第一次呼叫函數時就不會損失效能了,只在程式碼載入時會損失一點效能

  以下就是依照這個想法重寫的addEvent()。以下程式碼建立了一個匿名的自執行函數,透過不同的分支以決定應該使用哪個函數實作

var addEvent = (function () {
    if (document.addEventListener) {
            return function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    }    
    else if (document.attachEvent) {
            return function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    }    
    else { 
           return function (type, element, fun) {
            element['on' + type] = fun;
        }
    }
})();
登入後複製

函數綁定

在javascript與DOM互動中經常需要使用函數綁定,定義一個函數然後將其綁定到特定DOM元素或集合的某個事件觸發程序上,綁定函數經常和回調函數及事件處理程序一起使用,以便把函數作為變量傳遞的同時保留程式碼執行環境

<button id="btn">按钮</button><script>            
    var handler={
        message:"Event handled.",
        handlerFun:function(){
            alert(this.message);
        }
    };
btn.onclick = handler.handlerFun;
</script>
登入後複製

上面的程式碼建立了一個叫做handler的物件。 handler.handlerFun()方法被指派為一個DOM按鈕的事件處理程序。當按下該按鈕時,就呼叫該函數,顯示一個警告框。雖然看起來像警告框應該顯示Event handled,然而實際上顯示的是undefiend。這個問題在於沒有儲存handler.handleClick()的環境,所以this物件最後是指向了DOM按鈕而非handler

  可以用閉包來修正這個問題

<button id="btn">按钮</button>
<script>            
var handler={
    message:"Event handled.",
    handlerFun:function(){
        alert(this.message);
    }
};
btn.onclick = function(){
    handler.handlerFun();    
}
</script>
登入後複製

當然這是特定於此場景的解決方案,建立多個閉包可能會令程式碼難以理解和除錯。更好的方法是使用函數綁定

  一個簡單的綁定函數bind()接受一個函數和一個環境,​​並傳回一個在給定環境中呼叫給定函數的函數,並且將所有參數原封不動傳遞過去

function bind(fn,context){
    return function(){        
    return fn.apply(context,arguments);
    }
}
登入後複製

這個函數似乎簡單,但其功能是非常強大的。在bind()中建立了一個閉包,閉包使用apply()呼叫傳入的函數,並給apply()傳遞context物件和參數。當呼叫傳回的函數時,它會在給定環境中執行被傳入的函數並給出所有參數

<button id="btn">按钮</button><script>  function bind(fn,context){    return function(){        return fn.apply(context,arguments);
    }
}          
var handler={
    message:"Event handled.",
    handlerFun:function(){
        alert(this.message);
    }
};
btn.onclick = bind(handler.handlerFun,handler);
</script>
登入後複製

ECMAScript5為所有函數定義了一個原生的bind()方法,進一步簡化了操作

  只要是将某个函数指针以值的形式进行传递,同时该函数必须在特定环境中执行,被绑定函数的效用就突显出来了。它们主要用于事件处理程序以及setTimeout()和setInterval()。然而,被绑定函数与普通函数相比有更多的开销,它们需要更多内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用

函数柯里化

与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数

function add(num1,num2){
    return num1+num2;
}function curriedAdd(num2){
    return add(5,num2);
}
console.log(add(2,3));//5console.log(curriedAdd(3));//8
登入後複製

这段代码定义了两个函数:add()和curriedAdd()。后者本质上是在任何情况下第一个参数为5的add()版本。尽管从技术来说curriedAdd()并非柯里化的函数,但它很好地展示了其概念

  柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。下面是创建柯里化函数的通用方式

function curry(fn){
    var args = Array.prototype.slice.call(arguments, 1);    
    return function(){        
    var innerArgs = Array.prototype.slice.call(arguments),
        finalArgs = args.concat(innerArgs);        
        return fn.apply(null, finalArgs);
    };
}
登入後複製

curry()函数的主要工作就是将被返回函数的参数进行排序。curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次用到了slice())。有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将它们组合为finalArgs,然后使用apply()将结果传递给函数。注意这个函数并没有考虑到执行环境,所以调用apply()时第一个参数是null。curry()函数可以按以下方式应用

function add(num1, num2){    
return num1 + num2;
}var curriedAdd = curry(add, 5);
alert(curriedAdd(3)); //8
登入後複製

在这个例子中,创建了第一个参数绑定为5的add()的柯里化版本。当调用cuurriedAdd()并传入3时,3会成为add()的第二个参数,同时第一个参数依然是5,最后结果便是和8。也可以像下例这样给出所有的函数参数:

function add(num1, num2){
    return num1 + num2;
}
var curriedAdd2 = curry(add, 5, 12);
alert(curriedAdd2()); //17
登入後複製

在这里,柯里化的add()函数两个参数都提供了,所以以后就无需再传递给它们了

函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数

function bind(fn, context){
    var args = Array.prototype.slice.call(arguments, 2);    
    return function(){        
    var innerArgs = Array.prototype.slice.call(arguments),
        finalArgs = args.concat(innerArgs);        
        return fn.apply(context, finalArgs);
    };
}
登入後複製

对curry()函数的主要更改在于传入的参数个数,以及它如何影响代码的结果。curry()仅仅接受一个要包裹的函数作为参数,而bind()同时接受函数和一个object对象。这表示给被绑定的函数的参数是从第三个开始而不是第二个,这就要更改slice()的第一处调用。另一处更改是在倒数第3行将object对象传给apply()。当使用bind()时,它会返回绑定到给定环境的函数,并且可能它其中某些函数参数已经被设好。要想除了event对象再额外给事件处理程序传递参数时,这非常有用

var handler = {
    message: "Event handled",
    handleClick: function(name, event){
        alert(this.message + ":" + name + ":" + event.type);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));
登入後複製

handler.handleClick()方法接受了两个参数:要处理的元素的名字和event对象。作为第三个参数传递给bind()函数的名字,又被传递给了handler.handleClick(),而handler.handleClick()也会同时接收到event对象

ECMAScript5的bind()方法也实现函数柯里化,只要在this的值之后再传入另一个参数即可

var handler = {
    message: "Event handled",
    handleClick: function(name, event){
        alert(this.message + ":" + name + ":" + event.type);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler, "my-btn"));
登入後複製

javaScript中的柯里化函数和绑定函数提供了强大的动态函数创建功能。使用bind()还是curry()要根据是否需要object对象响应来决定。它们都能用于创建复杂的算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销

函数重写

由于一个函数可以返回另一个函数,因此可以用新的函数来覆盖旧的函数

function a(){
    console.log('a');
    a = function(){
        console.log('b');
    }
}
登入後複製

这样一来,当我们第一次调用该函数时会console.log('a')会被执行;全局变量a被重定义,并被赋予新的函数

当该函数再次被调用时, console.log('b')会被执行

再复杂一点的情况如下所示

var a = (function(){
    function someSetup(){
            var setup = 'done';
    }
    function actualWork(){
        console.log('work');
    }
    someSetup();    
    return actualWork;
})()
登入後複製

我们使用了私有函数someSetup()和actualWork(),当函数a()第一次被调用时,它会调用someSetup(),并返回函数actualWork()的引用.

以上是javascript函數的五個運用技巧介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

PHP與Vue:完美搭檔的前端開發利器 PHP與Vue:完美搭檔的前端開發利器 Mar 16, 2024 pm 12:09 PM

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

前端面試官常問的問題 前端面試官常問的問題 Mar 19, 2024 pm 02:24 PM

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

Django是前端還是後端?一探究竟! Django是前端還是後端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

Go語言前端技術探秘:前端開發新視野 Go語言前端技術探秘:前端開發新視野 Mar 28, 2024 pm 01:06 PM

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

Golang與前端技術結合:探討Golang如何在前端領域發揮作用 Golang與前端技術結合:探討Golang如何在前端領域發揮作用 Mar 19, 2024 pm 06:15 PM

Golang與前端技術結合:探討Golang如何在前端領域發揮作用,需要具體程式碼範例隨著互聯網和行動應用的快速發展,前端技術也愈發重要。而在這個領域中,Golang作為一門強大的後端程式語言,也可以發揮重要作用。本文將探討Golang如何與前端技術結合,以及透過具體的程式碼範例來展示其在前端領域的潛力。 Golang在前端領域的角色作為一門高效、簡潔且易於學習的

See all articles