淺談JavaScript函式過載
阿新 • • 發佈:2018-12-23
上個星期四下午,接到了網易的視訊面試(前端實習生第二輪技術面試)。面了一個多小時,自我感覺面試得很糟糕的,因為問到的很多問題都很難,根本回答不上來。不過那天晚上,還是很驚喜的接到了HR面電話。現在HR面試的結果還沒有出來,聽說要等到下週二才出,所以再好好等幾天哈。
前面說了這多的廢話,現在是時候和夥伴們分享一下面試乾貨哈。因為二面問到的內容還挺多的,所以這裡就不全部列舉出來了。這裡只討論一下函式的過載。 下面是面試時的對話,“面”指面試官,“我”就是我~ 面:你能說說JS怎麼實現函式的過載嗎? 我:因為JS的引數是可變長度的,是沒有過載的!也是沒必要用過載的!function overLoading() { // 根據arguments.length,對不同的值進行不同的操作 switch(arguments.length) { case 0: /*操作1的程式碼寫在這裡*/ break; case 1: /*操作2的程式碼寫在這裡*/ break; case 2: /*操作3的程式碼寫在這裡*/ //後面還有很多的case...... } }
我把程式碼發給了面試官。
var people = { values: ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"] };
我們希望people物件擁有一個find方法,當不傳任何引數時,就會把people.values裡面的所有元素返回來;當傳一個引數時,就把first-name跟這個引數匹配的元素返回來;當傳兩個引數時,則把first-name和last-name都匹配的才返回來。因為find方法是根據引數的個數不同而執行不同的操作的,所以,我們希望有一個addMethod方法,能夠如下的為people新增find的過載:
addMethod(people, "find", function() {}); /*不傳參*/ addMethod(people, "find", function(a) {}); /*傳一個*/ addMethod(people, "find", function(a, b) {}); /*傳兩個*/
這時候問題來了,這個全域性的addMethod方法該怎麼實現呢?John Resig的實現方法如下,程式碼不長,但是非常的巧妙:
function addMethod(object, name, fn) { var old = object[name]; //把前一次新增的方法存在一個臨時變數old裡面 object[name] = function() { // 重寫了object[name]的方法 // 如果呼叫object[name]方法時,傳入的引數個數跟預期的一致,則直接呼叫 if(fn.length === arguments.length) { return fn.apply(this, arguments); // 否則,判斷old是否是函式,如果是,就呼叫old } else if(typeof old === "function") { return old.apply(this, arguments); } } }
現在,我們一起來分析一個這個addMethod函式,它接收3個引數,第一個為要繫結方法的物件,第二個為繫結的方法名稱,第三個為需要繫結的方法(一個匿名函式)。函式體的的分析已經在註釋裡面了。
OK,現在這個addMethod方法已經實現了,我們接下來就實現people.find的過載啦!全部程式碼如下://addMethod function addMethod(object, name, fn) { var old = object[name]; object[name] = function() { if(fn.length === arguments.length) { return fn.apply(this, arguments); } else if(typeof old === "function") { return old.apply(this, arguments); } } } var people = { values: ["Dean Edwards", "Alex Russell", "Dean Tom"] }; /* 下面開始通過addMethod來實現對people.find方法的過載 */ // 不傳引數時,返回peopld.values裡面的所有元素 addMethod(people, "find", function() { return this.values; }); // 傳一個引數時,按first-name的匹配進行返回 addMethod(people, "find", function(firstName) { 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; }); // 傳兩個引數時,返回first-name和last-name都匹配的元素 addMethod(people, "find", function(firstName, lastName) { 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()); //["Dean Edwards", "Alex Russell", "Dean Tom"] console.log(people.find("Dean")); //["Dean Edwards", "Dean Tom"] console.log(people.find("Dean Edwards")); //["Dean Edwards"]
好啦,實現JS函式過載就寫這麼多啦,如果親們有更好的實現方法,歡迎評論交流哈~