你們都知道,所謂重載,就是一組相同的函數名,有不一樣個數的參數,在使用時調用一個函數名,傳入不一樣參數,根據你的參數個數,來決定使用不一樣的函數!重載這個在JAVA這些經典的編程語言裏面都很好用,能夠說調用同一個方法名用不一樣的參數就能夠隨心所欲了。前端
可是咱們知道JavaScript中是沒有重載的(爲何沒重載?不是JAVA的特性JavaScript也會有的嗎?),由於後面定義的函數會覆蓋前面的同名函數,可是重載那麼好用,咱們想在JavaScript實現函數重載該怎麼辦呢?編程
今天就來給你們講講在JavaScript裏面實現函數重載的兩個思路。(零基礎的同窗打擾了,這篇不太適合你,須要點面向對象基礎。)數組
這種方法比較簡單,給一個思路,你們確定都能理解,就是函數內部用switch語句,根據傳入參數的個數調用不一樣的case語句,從而功能上達到重載的效果。
這種方法簡單粗暴。可是對於一個正在學習js的人來講,這種方法未免太敷衍了。(那麼沒技術含量,怎麼能讓我變成前端開發大神呢?)閉包
下面重點介紹一下第二種,老實說我第一次看的時候很吃力,看了一個小時才捋清楚,由於有的知識點雖然看過了可是不熟悉。(乾貨很足,別看走神)app
咱們這個例子,是若是你不傳入參數,就會輸出全部的人,輸入firstname,就會輸出匹配的人,若是輸入全名的人,也會輸出匹配的人。若是用重載的話,用戶體驗確實會很好(這個例子是我之前學習時從網上扒下來的,很經典,具備表明性,可是他們都沒有寫實現過程,因此今天我來給你們說講一下)編程語言
//第二種實現重載的方法 function method(obj,name,fnc){ var old = obj[name]; console.log(old instanceof Function); obj[name] = function(){ console.log(arguments.length+" "+fnc.length); if(arguments.length === fnc.length){//判斷參數是否對應 return fnc.apply(this,arguments);//指向對應的函數 }else if(typeof old === "function"){ return old.apply(this,arguments); } } } //定義一個用來查找和輸出的數組 var people = { values:["Zhang san","Li si","Wang wu"] }; //重載無參數查找方法,會輸出全部人 method(people,"find",function(){ console.log("無參數"); return this.values; }) //重載1個參數查找方法,輸入firstname參數,找打匹配firstname的人 method(people,"find",function(firstname){ console.log("一個參數"); var ret = []; for(var i = 0;i < this.values.length;i++){ if(this.values[i].indexOf(firstname) === 0){ ret.push(this.values[i]) } } return ret; }) //重載2個參數查找方法,輸入全名,找到對應的人 method(people,"find",function(firstname,lastname){ console.log("兩個參數"); var ret = []; for(var i = 0;i < this.values.length;i++){ if(this.values[i] == firstname + " " + lastname){ ret.push(this.values[i]) } } return ret; }) //調用 console.log(people.find()); console.log(people.find("Zhang"));
思路:這段代碼第一眼看的時候確定是懵的,再看一次好像有點思路,再看就又懵了。
其實呢,這種方法巧妙的運用了JavaScript的閉包原理(重點),既然js後面的函數會覆蓋前面的同名函數,我就強行讓全部的函數都留在內存裏,等我須要的時候再去找它。
有了這個想法,是否是就想到了閉包,函數外訪問函數內的變量,從而使函數留在內存中不被刪除。這就是閉包的核心做用。函數
實現過程:
咱們看一下上面這段代碼,最重要的是method方法的定義:這個方法中最重要的一點就是這個old,這個old真的很巧妙。它的做用至關於一個指針,指向上一次被調用的method函數,這樣說可能有點不太懂,咱們根據代碼來講,js的解析順序從上到下爲。
1.解析method(先無論裏面的東西)
2.method(people,"find",function() ) 執行這句的時候,它就回去執行上面定義的方法,而後此時old的值爲空,由於你尚未定義過這個函數,因此它此時是undefined。
而後繼續執行,這時候咱們才定義 obj[name] = function()。學習
而後js解析的時候發現返回了fnc函數,更重要的是fnc函數裏面還調用了method裏面的變量,這不就是閉包了!
由於fnc函數的實現是在調用時候纔會去實現,因此js就想,這我執行完也不能刪除啊,要不外面那個用啥,就留着吧先(此處用apply函數改變了fnc函數內部的this指向)
3.好了第一次method的使用結束了,開始了第二句,method(people,"find",function(firstname) 而後此次使用的時候,又要執行old = obj[name]。
此時的old是什麼,是函數了,由於上一條語句定義過了,並且沒有刪除,那我此次的old實際上指向的是上次定義的方法,它起的做用好像一個指針,指向了上一次定義的 obj[name]。
而後繼續往下解析,又是閉包,還得留着。
4.第三句的method調用開始了,同理old指向的是上次定義的 obj[name] 一樣也仍是閉包,還得留着。
5.到這裏,內存中實際上有三個 obj[name],由於三次method的內存都沒有刪除,這是否是實現了三個函數共存,同時還能夠用old將它們聯繫起來是否是很巧妙
6.咱們 people.find() 的時候,就會最早調用最後一次調用method時定義的function,若是參數個數相同 也就是 arguments.length === fnc.length 那麼就執行就行了,也不用找別的函數了,若是不相同的話,那就得用到old了 return old.apply(this,arguments); this
old指向的是上次method調用時定義的函數,因此咱們就去上一次的找,若是找到了,繼續執行 arguments.length === fnc.length 若是找不到,再次調用old 繼續向上找,只要你定義過,確定能找到的。spa
總結:運用閉包的原理使三個函數共存於內存中,old至關於一個指針,指向上一次定義的function,每次調用的時候,決定是否須要尋找。
最後來看看執行輸出結果:
執行過程很容易說明這一點:首先第一次調用的時候 old確定不是函數,因此instance判斷是false,繼續調用的話就會爲true。
而後,咱們調用method的順序,是從沒有參數到兩個參數,因此咱們最早調用find方法,是最後一次method調用時定義的,因此fnc的length長度是2.而後向上找,length爲1,最後終於找到了length爲0的而後執行,輸出。
好了,今天的內容就那麼多吧!要是你也喜歡,就轉發給更多朋友學習吧!
喜歡的朋友也能夠關注個人公衆號:網頁前端開發學習,發現更多好文哦!