「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。
在介绍 JS 里的函数唯一标识和自记忆函数之前,需要明确一个概念,函数可以像对象一样,动态创建和分配属性。
函数也是对象
JS 里,一切皆是对象,函数也不例外,废话不多说,直接测试一下,
对象拥有的能力,函数都有
函数也是对象,对象能做的任何一件事,函数都能做。唯一的区别是函数是可调用的(invokable),即函数会被调用以便执行某项动作。
对象
- 对象可以通过字面量来创建。
const obj = {}
- 对象可以赋值给变量、数组项,或其他对象的属性。
const obj = {} // 赋值给变量
const arr = []
arr.push(obj) // 赋值给数组项
obj.data = {} // 赋值给其他对象的属性
- 对象可以作为函数的入参和出参。
function fn (obj) {
return {
obj
}
}
fn({ name: 'lin'})
- 对象可以动态创建和分配属性。
const obj = {}
obj.name = 'lin'
函数
- 函数可以通过字面量来创建。
function fn () {}
- 函数可以赋值给变量、数组项,或其他对象的属性。
const fn = function () {} // 赋值给变量
const arr = []
arr.push(fn) // 赋值给数组项
const obj = {}
obj.fn = fn // 赋值给其他对象的属性
- 函数可以作为函数的入参和出参。
function fn (callback) {
return callback()
}
fn(() => {
console.log('hello')
})
- 函数可以动态创建和分配属性。
function fn () {}
fn.name = 'lin'
fn.age = 18
函数作为对象的一些用途
函数唯一标识
给函数设置一个 id 属性,作为唯一标识,在某些情况下可以提高性能,比如,
一个集合中的函数,不希望出现重复函数
const store = {
nextId: 1,
cache: {},
add (fn) {
if (!fn.id) {
fn.id = this.nextId++
this.cache[fn.id] = fn
}
}
}
测试一下,
function fn1 () {}
function fn2 () {}
store.add(fn1)
store.add(fn1) // add了两个相同的函数
store.add(fn2)
console.log(store.cache)
添加了两次 fn1 ,最后存储下来的只有一个,如下图,
这种写法可以用于管理事件发生后需要调用的回调函数集合,已经存在于集合中的函数就不要再存进去了,提高性能。
自记忆函数
通过给函数添加属性来记住一些计算结果,之后再调用的时候就可以不用重新计算了,提高性能,以计算素数为例,
function isPrime (value) {
if (!isPrime.cache) {
isPrime.cache = {} // 给函数添加一个 cache 来记住计算结果
}
if (isPrime.cache[value] !== undefined) {
console.log(`缓存里有${value},直接返回`)
return isPrime.cache[value] // 如果有值就直接返回
}
let prime = value > 2 // 计算
for (let i = 2; i < value; i++) {
if (value % i === 0) {
prime = false
break
}
}
console.log(`缓存里没有${value},存进去`)
return isPrime.cache[value] = prime // 如果是第一次计算,就存值
}
测试一下,
isPrime(3)
isPrime(4)
isPrime(5)
isPrime(5)
isPrime(5) // 多次计算 5
console.log('isPrime.cache :>> ', isPrime.cache)
计算素数只是简单的计算,但如果用于处理复杂的计算,比如动画中的计算、搜索不经常变化的数据、耗时的数学运算等,对性能的提升无疑是巨大的。
小结
给函数添加属性的写法有利有弊:
- 好处是能把属于这个函数的功能集中在一起;
- 坏处是纯粹主义者会认为逻辑混合太多,函数应该只需要把一件事做好
仁者见仁,智者见智,纯粹的函数式编程有人做大量实践,给函数添加属性也有人做大量实践,比如 React 源码中的
FunctionComponent
,也在函数上定义了一大堆属性呢。
对于我们普通开发者而言,平时开发中能用就用,即使用不了,了解一下,开拓视野也挺好的。
如果我的文章对你有帮助,你的赞👍就是对我的最大支持^_^