Javascript中函式作为物件的魅力
Javascript赋予了函式非常多的特性,其中最重要的特性之一就是将函式作为第一型的物件。那就意味着在javascript中函式可以有属性,可以有方法, 可以享有所有物件所拥有的特性。并且最重要的,她还可以直接被呼叫
我们简单的试验一下就可以发现
// 简单实验 函式作为物件的存在
let fn = function () {}
fn.prop = \'fnProp\'
console.log(fn.prop) // fnProp
为函式新增属性的这个特性我觉的大家在平时的开发中基本没什么尝试或者是使用过,但是在一些JS库或者是事件回掉管理中都能发挥出很大的用处。下面一起来看几个例子。
函式快取
在某有一些的情况下我们可以要储存一组相关但是相互又独立的函式。这个需求看起来很easy,实现起来也不复杂。最显而易见的做法是使用一个数组来储存所有的函式,
这样不是不可以,但是显然这种做法不是最好的。下面通过为函式属性我们呢来实现这个我们的目的
// 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()方法用来设定储存,先来判断当前函式是否已经在快取中然后再去设定快取,这样就能限制函式的重复新增,最后返回true。
!!构造是一种可以将任意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 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:伪造阵列方法
//
//
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]); //
console.log(elems[1]); //
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忍者秘籍》
迎大家多多留言讨论,如有错误请大神指教,如果你是小白也可以私信“资料”领取前端学习资料一起学习
