摘要:作用域安全的構造函數會首先確認對象是正確類型的實例,然后再進行更改,如下這樣就避免了在全局對象上意外更改或設置屬性。在多人協作的項目中,為了避免他們誤改了全局對象,也應使用作用域安全的構造函數。
博客原文地址:Claiyre的個人博客
如需轉載,請在文章開頭注明原文地址
在JavaScript中,函數的功能十分強大。它們是第一類對象,也可以作為另一個對象的方法,還可以作為參數傳入另一個函數,不僅如此,還能被一個函數返回!可以說,在JS中,函數無處不在,無所不能,堪比孫猴子呀!當你運用好函數時,它能助你取西經,讓代碼變得優雅簡潔,運用不好時,那就遭殃了,要大鬧天宮咯~
除了函數相關的基礎知識外,掌握一些高級函數并應用起來,不僅能讓JS代碼看起來更為精簡,還可以提升性能。以下是博主總結的一些常用的、重要的高級函數,加上了一些個人見解,特此記錄下來。如果您是JS初學者,也不要被“高級”兩個字嚇到,因為文中穿插講解了一些原型、this等基礎知識,相信并不難理解。如果您是JS大牛,也可以把本文用來查漏補缺。
function Person(name,age){ this.name = name; this.age = age; } var p1 = new Person("Claiyre",80);
相信您對上面的構造函數一定不陌生,但是,,如果某個粗心的程序猿調用這個構造函數時忘記加new了會發生什么?
var p3 = Person("Tom",30); console.log(p3); //undefined console.log(window.name); //Tom
由于使用了不安全的構造函數,上面的代碼意外的改變了window的name,因為this對象是在運行時綁定的,使用new調用構造函數時this是指向新創建的對象的,不使用new時,this是指向window的。
由于window的name屬性是用來識別鏈接目標和frame的,所在這里對該屬性的偶然覆蓋可能導致其他錯誤。
作用域安全的構造函數會首先確認this對象是正確類型的實例,然后再進行更改,如下:
function Person(name,age){ if(this instanceof Person){ this.name = name; this.age = age; } else { return new Person(name,age); } }
這樣就避免了在全局對象上意外更改或設置屬性。
實現這個安全模式,相當于鎖定了調用構造函數的環境,因此借用構造函數繼承模式可能會出現問題,解決方法是組合使用原型鏈和構造函數模式,即組合繼承。
如果您是一個JS庫或框架的開發者,相信作用域安全的構造函數一定對您非常有用。在多人協作的項目中,為了避免他們誤改了全局對象,也應使用作用域安全的構造函數。
由于瀏覽器間的行為差異,代碼中可能會有許多檢測瀏覽器行為的if語句。但用戶的瀏覽器若支持某一特性,便會一直支持,所以這些if語句,只用被執行一次,即便只有一個if語句的代碼,也比沒有要快。
惰性載入表示函數執行的分支僅會執行一次,有兩種實現惰性載入的方式,第一種就是在函數第一次被調用時再處理函數,用檢測到的結果重寫原函數。
function detection(){ if(//支持某特性){ detection = function(){ //直接用支持的特性 } } else if(//支持第二種特性){ detection = function(){ //用第二種特性 } } else { detection = function(){ //用其他解決方案 } } }
第二種實現惰性載入的方式是在聲明函數時就指定適當的函數
var detection = (function(){ if(//支持某特性){ return function(){ //直接用支持的特性 } } else if(//支持第二種特性){ return function(){ //用第二種特性 } } else { return function(){ //用其他解決方案 } } })();
惰性載入函數的有點是在只初次執行時犧牲一點性能,之后便不會再有多余的消耗性能。
函數綁定作用域在JS中,函數的作用域是在函數被調用時動態綁定的,也就是說函數的this對象的指向是不定的,但在一些情況下,我們需要讓某一函數的執行作用域固定,總是指向某一對象。這時怎么辦呢?
當當當~~可以用函數綁定作用域函數呀
function bind(fn,context){ return function(){ return fn.apply(context,arguments); } }
用法:
var person1 = { name: "claiyre", sayName: function(){ alert(this.name); } } var sayPerson1Name = bind(person1.sayName,person1); sayPerson1Name(); //claiyre
call函數和apply函數可以臨時改變函數的作用域,使用bind函數可以得到一個綁定了作用域的函數
函數柯里化(curry)curry的概念很簡單:只傳遞部分參數來調用函數,然后讓函數返回另一個函數去處理剩下的參數。可以理解為賦予了函數“加載”的能力。
許多js庫中都封裝了curry函數,具體使用可以這樣。
var match = curry(function(what,str){ return str.match(what) }); var hasNumber = match(/[0-9]+/g); var hasSpace = match(/s+/g) hasNumber("123asd"); //["123"] hasNumber("hello world!"); //null hasSpace("hello world!"); //[" "]; hasSpace("hello"); //null console.log(match(/s+/g,"i am Claiyre")); //直接全部傳參也可: [" "," "]
一旦函數經過柯里化,我們就可以先傳遞部分參數調用它,然后得到一個更具體的函數。這個更具體的函數通過閉包幫我們記住了第一次傳遞的參數,最后我們就可以用這個更具體的函數為所欲為啦~
一個較為簡單的實現curry的方式:
function curry(fn){ var i = 0; var outer = Array.prototype.slice.call(arguments,1); var len = fn.length; return function(){ var inner = outer.concat(Array.prototype.slice.call(arguments)); return inner.length === len?fn.apply(null,inner):function (){ var finalArgs = inner.concat(Array.prototype.slice.call(arguments)); return fn.apply(null,finalArgs); } } }debounce函數
debounce函數,又稱“去抖函數”。它的功能也很簡單直接,就是防止某一函數被連續調用,從而導致瀏覽器卡死或崩潰。用法如下:
var myFunc = debounce(function(){ //繁重、耗性能的操作 },250); window.addEventListener("resize",myFunc);
像窗口的resize,這類可以以較高的速率觸發的事件,非常適合用去抖函數,這時也可稱作“函數節流”,避免給瀏覽器帶來過大的性能負擔。
具體的實現時,當函數被調用時,不立即執行相應的語句,而是等待固定的時間w,若在w時間內,即等待還未結束時,函數又被調用了一次,則再等待w時間,重復上述過程,直到最后一次被調用后的w時間內該函數都沒有被再調用,則執行相應的代碼。
實現代碼如下:
function debounce(fn,wait){ var td; return function(){ clearTimeout(td); td= setTimeout(fn,wait); } }once函數
顧名思義,once函數是僅僅會被執行一次的函數。具體實現如下:
function once(fn){ var result; return function(){ if(fn){ result = fn(arguments); fn = null; } return result; } } var init = once(function(){ //初始化操作 })
在被執行過一次后,參數fn就被賦值null了,那么在接下來被調用時,便再也不會進入到if語句中了,也就是第一次被調用后,該函數永遠不會被執行了。
還可以對上述once函數進行改進,不僅可以傳入函數,同時還可以給傳入的函數綁定作用域u,同時實現了bind和once。
function once(fn,context){ var result; return function(){ if(fn){ result = fn.apply(context,arguments); fn = null; } return result; } }結語
通過以上的閱讀,不難發現很多“高級函數”的實現其實并不復雜,數十行代碼便可搞定,但重要的是能真正理解它們的原理,在實際中適時地應用,以此性能提升,讓代碼簡潔,邏輯清晰
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/87278.html
摘要:換句話說,定義在閉包中的函數可以記憶它被創建時候的環境。詞法環境的概念定義摘自百科。一個詞法環境由一個環境記錄項和可能為空的外部詞法環境引用構成。中使用詞法環境管理靜態作用域。 一個資深的同事在我出發去面試前告誡我,問JS知識點的時候千萬別主動提閉包,它就是一個坑啊!坑啊!啊! 閉包確實是js的難點和重點,其實也沒那么可怕,關鍵是機制的理解,可以和函數一起單獨拿出來說說,其實關于閉包的...
摘要:原文地址游客前言金三銀四,很多同學心里大概都準備著年后找工作或者跳槽。最近有很多同學都在交流群里求大廠面試題。 最近整理了一波面試題,包括安卓JAVA方面的,目前大廠還是以安卓源碼,算法,以及數據結構為主,有一些中小型公司也會問到混合開發的知識,至于我為什么傾向于混合開發,我的一句話就是走上編程之路,將來你要學不僅僅是這些,豐富自己方能與世接軌,做好全棧的裝備。 原文地址:游客kutd...
摘要:在這里談一談實踐過程中遇到的問題,基礎的用法不再說明了,可以自行百度。一般傳入的參數為。當然中的聚合命令不止這些,用法大同小異如果要實現一些高級功能,的基本命令滿足不了你,可能就要使用這個了。 前言 最近在項目中使用mongodb進行簡單的數據分析,在使用mongodb驅動mgo時遇到一些問題,比如在mongodb中執行命令成功,到了mgo中就執行失敗。在這里談一談實踐過程中遇到的問題...
插件顧名思義就是能在一個頁面多處使用, 各自按自己的參數配置運行, 并且相互不會沖突.會寫javascript插件是進階js高級的必經之路, 也是自己所學知識的一個典型的綜合運用. 如果你還沒頭緒, 無從下手的話, 不用著急, 今天我們就一起來探討一下插件的一般寫法.所需技能: 1.面向對象用法 2.閉包的理解 3.變量作用域的理解 以一個tab選項卡的為例: 第一步: 我們需要寫html結...
閱讀 2077·2023-04-25 22:58
閱讀 1432·2021-09-22 15:20
閱讀 2709·2019-08-30 15:56
閱讀 2003·2019-08-30 15:54
閱讀 2121·2019-08-29 12:31
閱讀 2743·2019-08-26 13:37
閱讀 606·2019-08-26 13:25
閱讀 2109·2019-08-26 11:58