1. 程式人生 > 程式設計 >JavaScript函式過載操作例項淺析

JavaScript函式過載操作例項淺析

本文例項講述了JavaScript函式過載操作。分享給大家供大家參考,具體如下:

上個星期四下午,接到了網易的視訊面試(前端實習生第二輪技術面試)。面了一個多小時,自我感覺面試得很糟糕的,因為問到的很多問題都很難,根本回答不上來。不過那天晚上,還是很驚喜的接到了HR面電話。現在HR面試的結果還沒有出來,聽說要等到下週二才出,所以再好好等幾天哈。

前面說了這多的廢話,現在是時候和夥伴們分享一下面試乾貨哈。因為二面問到的內容還挺多的,所以這裡就不全部列舉出來了。這裡只討論一下函式的過載。

下面是面試時的對話,“面”指面試官,“我”就是我~

面:你能說說JS怎麼實現函式的過載嗎?
我:因為JS的引數是可變長度的,是沒有過載的!也是沒必要用過載的!

面:怎麼沒必要使用過載?你先告訴什麼是過載?
我: 過載就是一組具有相同名字、不同引數列表的函式(方法)。
面:對的,那為什麼你還說JS沒有過載,也沒必要使用過載呢?

我當時一臉懵逼了,因為不知道面試官到底是想要考我什麼,因為我記得《JS高階程式設計》裡是提到過函式是沒有過載的啊(後來查了一下,在第三版的66頁,親們可以自己翻開書本看看),但是現在面試官不同意我的回答啊,就是說在他看來,JS是有過載的,我不能堅持說沒有過載啊。所以我就往過載的概念方向靜靜的思考了片刻,然後想到了使用arguments物件進行判斷。於是:
我:我覺得,如果JS函式需要實現過載的話,可以根據arguments物件的length值進行判斷。

面: 你可以寫個例子出來給我看嗎?
然後,我就在輸入框裡面寫了如下的程式碼:

function overLoading() {
  // 根據arguments.length,對不同的值進行不同的操作
  switch(arguments.length) {
    case 0:
      /*操作1的程式碼寫在這裡*/
      break;
    case 1:
      /*操作2的程式碼寫在這裡*/
      break;
    case 2:
      /*操作3的程式碼寫在這裡*/
       
  //後面還有很多的case......
}
 
}

我把程式碼發給了面試官。

面:對,這就是過載的一種實現的方法!不過你能不能想出一個更好的方法呢?
我: 暫時就想到這一種方法了。

好吧,跟面試官的對話就寫這麼多了。他說問我能不能想出一個更好的辦法,意味著肯定還有其他我不知道的方法。所以,後來就開始翻書本查詢。哈哈,終於在JQuery之父John Resig寫的《secrets of the JavaScript ninja》找到了一個絕佳巧妙的方法!那種方法充分的利用了閉包的特性!

在介紹這個方法之前,我們先來看看外國人名字組成哈,比如,John Resig,John是first-name,Resig是last-name,就相當於我們的姓名由姓和名組成一樣。

我們現在有這樣的一個需求,有一個people物件,裡面存著一些人名,如下:

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,function(a) {}); /*傳一個*/
addMethod(people,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,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","Dean Tom"]
};
 
/* 下面開始通過addMethod來實現對people.find方法的過載 */
 
// 不傳引數時,返回peopld.values裡面的所有元素
addMethod(people,function() {
  return this.values;
});
 
// 傳一個引數時,按first-name的匹配進行返回
addMethod(people,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,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","Dean Tom"]
console.log(people.find("Dean")); //["Dean Edwards","Dean Tom"]
console.log(people.find("Dean Edwards")); //["Dean Edwards"]

好啦,實現JS函式過載就寫這麼多啦,如果親們有更好的實現方法,歡迎評論交流哈~

感興趣的朋友可以使用線上HTML/CSS/JavaScript程式碼執行工具:http://tools.jb51.net/code/HtmlJsRun測試上述程式碼執行效果。

更多關於JavaScript相關內容感興趣的讀者可檢視本站專題:《javascript面向物件入門教程》、《JavaScript錯誤與除錯技巧總結》、《JavaScript資料結構與演算法技巧總結》、《JavaScript遍歷演算法與技巧總結》及《JavaScript數學運算用法總結》

希望本文所述對大家JavaScript程式設計有所幫助。