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表达式转化为其等效布尔值的简单方式。

缓存记忆函数

这种函数能够记住以前已经计算过的结果,避免了没必要要的计算,这显然是可以提高代码性能的。算法

在举例以前咱们先来看看这种方式的优缺点
优势数组

  • 缓存了以前的结果,最终用户享有性能优点
  • 其实是发生在幕后,操做无感

缺点缓存

  • 内存的牺牲这是确定的
  • 打破了存粹性(一个函数或者方法应该只作好一件事)
  • 若是方法中有算法,那么很难测量这个算法的性能

了解了优缺点咱们来看一个简单的计算素数的例子(不是很严谨)函数

// 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]的时候不须要通过任何的计算,可是大型的计算要主要内存的使用post

缓存记忆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中高阶函数的魅力, 有兴趣的话能够看一看。

代码地址

原文地址 若是以为有帮助的得话给个⭐吧😁

相关文章
相关标签/搜索