Javascript中函數做爲對象的魅力

Javascript賦予了函數很是多的特性,其中最重要的特性之一就是將函數做爲第一型的對象。那就意味着在javascript函數能夠有屬性,能夠有方法, 能夠享有全部對象所擁有的特性。而且最重要的,她還能夠直接被調用javascript

咱們簡單的試驗一下就能夠發現前端

// 簡單實驗 函數做爲對象的存在
let fn = function () {}
fn.prop = 'fnProp'
console.log(fn.prop) // fnProp
複製代碼

爲函數添加屬性的這個特性我覺的你們在平時的開發中基本沒什麼嘗試或者是使用過,可是在一些JS庫或者是事件回掉管理中都能發揮出很大的用處。下面一塊兒來看幾個例子。java

函數緩存

在某有一些的狀況下咱們能夠要存儲一組相關可是相互又獨立的函數。這個需求看起來很easy,實現起來也不復雜。最顯而易見的作法是使用一個數組來保存全部的函數, 這樣不是不能夠,可是顯然這種作法不是最好的。下面經過爲函數屬性咱們呢來實現這個咱們的目的git

// 1:函數緩存示例
let store = {
  nextId: 1, // id
  cache: {}, // 緩存
  add (fn) {
    // 若是函數中沒有id屬性那麼就緩存
    if (!fn.id) {
      console.log(`begin add func ${fn.name}`)
      fn.id = store.nextId ++
      // 設置完緩存以後返回true
      return !!(store.cache[fn.id] = fn)
    } else {
      console.log(`${fn.name} is already in cache`)
    }
  }
}
function storeCache() {}
store.add(storeCache) // begin add func storeCache
store.add(storeCache) // storeCache is already in cache
複製代碼

上面的這一段代碼邏輯清晰,store對象用來管理咱們的緩存,cache屬性用來存儲函數,nextId屬性用來保存當前的緩存Id,add()方法用來設置存儲,先來判斷當前函數是否已經在緩存中而後再去設置緩存,這樣就能限制函數的重複添加,最後返回truegithub

!!構造是一種能夠將任意Javascript表達式轉化爲其等效布爾值的簡單方式。算法

緩存記憶函數

這種函數能夠記住以前已經計算過的結果,避免了沒必要要的計算,這顯然是可以提高代碼性能的。數組

在舉例以前咱們先來看看這種方式的優缺點 優勢緩存

  • 緩存了以前的結果,最終用戶享有性能優點
  • 其實是發生在幕後,操做無感

缺點函數

  • 內存的犧牲這是確定的
  • 打破了存粹性(一個函數或者方法應該只作好一件事)
  • 若是方法中有算法,那麼很難測量這個算法的性能

瞭解了優缺點咱們來看一個簡單的計算素數的例子(不是很嚴謹)post

// 2: 緩存記憶函數
function isPrime (value) {
  if (!isPrime.anwers) isPrime.anwers = {}
  // 先從緩存裏面取
  if (isPrime.anwers[value] != null ) {
    return isPrime.anwers[value]
  }
  // 開始進行判斷和計算
  let prime = value != 1
  for (let index = 2; index < value; index++) {
    if (value % index == 0) {
      prime = false
      break;
    } 
  }
  // 保存計算出來的值
  return isPrime.anwers[value] = prime
}

console.log(isPrime(5))
console.log(`從函數記憶中直接讀取${isPrime.anwers[5]}`)
複製代碼

這裏呢 好處是特別明顯的咱們再次的取用isPrime.anwers[5]的時候不須要通過任何的計算,可是大型的計算要主要內存的使用

緩存記憶DOM元素

經過元素的標籤查詢DOM的操做的的代價是昂貴的,各位前端大佬確定都很清楚。咱們下面使用緩存記憶的方式來進行這個操做

// 3:緩存記憶DOM元素
function getElements (name) {
  if (!getElements.cache) getElements.cache = {}
  return getElements.cache[name] = getElements.cache[name] || document.getElementsByTagName(name);
}
console.log(getElements('div')) // HTMLCollection
console.log(getElements.cache['div']) // HTMLCollection
複製代碼

這個函數和上面的緩存使用的同一個手法,並且這簡單的4句代碼能爲咱們的性能帶來大幅度的提高。這也算是一種超能力吧。函數的不少特性都和其上下文有關,接下來咱們研究一個和上下文又換的例子。

僞造數組方法(上下文相關)

在一些狀況下咱們想建立一個包含一組數據的對象,可是這個數據包含不少的狀態,好比和集合項有關的元數據那麼咱們用數組來存就不太合適了。那麼這裏咱們就用對象的方式來假扮數組。經過改變上下文來完成一些「不法的行爲」

// 4:僞造數組方法
// <input type="button" id="add" >
// <input type="button" id="remove" >
let elems = {
  length: 0, //爲了保存個數
  add (elem) {
    Array.prototype.push.call(this, elem)
  },
  gather (id) {
    this.add(document.getElementById(id))
  }
}
elems.gather('add')
elems.gather('remove')
console.log(elems[0]); // <input type="button" id="add" >
console.log(elems[1]); // <input type="button" id="remove" >
console.log(elems.length); // 2
console.log(elems);
/** 0: input#add 1: input#remove add: ƒ add(elem) gather: ƒ gather(id) length: 2 */
複製代碼

在我還對JS懵懵懂懂的時候看到這樣的操做被秀了一臉,簡直是刺激了我幼小的心靈。

咱們在add函數中實現了把元素添加到了集合中,並且Array又正好提供push方法, 不用白不用。這種操做也是直白的展現了函數上下文的超強特性。

總結

Javascript強大的靈活性, 也帶來更多的可能性。 路漫漫其修遠兮,吾將上下而求索。

參考資料: 《JavaScript忍者祕籍》

關於函數我以前還寫過一篇JavaScript中高階函數的魅力, 有興趣的話能夠看一看。

代碼地址

原文地址 若是以爲有幫助的得話給個⭐吧😁

相關文章
相關標籤/搜索