重名就會被覆蓋?那JavaScript中是如何實現過載的呢?

weixin_34357887發表於2018-07-12
大家都知道,所謂過載,就是一組相同的函式名,有不同個數的引數,在使用時呼叫一個函式名,傳入不同引數,根據你的引數個數,來決定使用不同的函式!過載這個在JAVA這些經典的程式語言裡面都很好用,可以說呼叫同一個方法名用不同的引數就可以為所欲為了。
                                          

但是我們知道JavaScript中是沒有過載的(為什麼沒過載?不是JAVA的特性JavaScript也會有的嗎?),因為後面定義的函式會覆蓋前面的同名函式,但是過載那麼好用,我們想在JavaScript實現函式過載該怎麼辦呢?
                           
今天就來給大家講講在JavaScript裡面實現函式過載的兩個思路。(零基礎的同學打擾了,這篇不太適合你,需要點物件導向基礎。)
                                             
第一種方法:
這種方法比較簡單,給一個思路,大家肯定都能理解,就是函式內部用switch語句,根據傳入引數的個數呼叫不同的case語句,從而功能上達到過載的效果。
這種方法簡單粗暴。但是對於一個正在學習js的人來說,這種方法未免太敷衍了。(那麼沒技術含量,怎麼能讓我變成前端開發大神呢?)
                                              
下面重點介紹一下第二種,老實說我第一次看的時候很吃力,看了一個小時才捋清楚,因為有的知識點雖然看過了但是不熟悉。(乾貨很足,別看走神)
                                                          
第二種方法:
我們這個例子,是如果你不傳入引數,就會輸出所有的人,輸入firstname,就會輸出匹配的人,如果輸入全名的人,也會輸出匹配的人。如果用過載的話,使用者體驗確實會很好(這個例子是我以前學習時從網上扒下來的,很經典,具有代表性,但是他們都沒有寫實現過程,所以今天我來給大家說講一下)


思路:這段程式碼第一眼看的時候肯定是懵的,再看一次好像有點思路,再看就又懵了。
其實呢,這種方法巧妙的運用了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);
old指向的是上次method呼叫時定義的函式,所以我們就去上一次的找,如果找到了,繼續執行 arguments.length === fnc.length 如果找不到,再次呼叫old 繼續向上找,只要你定義過,肯定能找到的。

總結:運用閉包的原理使三個函式共存於記憶體中,old相當於一個指標,指向上一次定義的function,每次呼叫的時候,決定是否需要尋找。
最後來看看執行輸出結果:

執行過程很容易說明這一點:首先第一次呼叫的時候 old肯定不是函式,所以instance判斷是false,繼續呼叫的話就會為true。
然後,我們呼叫method的順序,是從沒有引數到兩個引數,所以我們最先呼叫find方法,是最後一次method呼叫時定義的,所以fnc的length長度是2.然後向上找,length為1,最後終於找到了length為0的然後執行,輸出。
好了,今天的內容就那麼多吧!要是你也喜歡,就轉發給更多朋友學習吧!


相關文章