likes
comments
collection
share

「前端每日一问(19)」JS 中函数为什么被称为一等公民?

作者站长头像
站长
· 阅读数 103

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

本题难度:⭐

JS 中为什么函数被称为一等公民?或者说函数为何是第一类对象?

答:

因为 JavaScript 中函数也是对象,函数拥有对象的所有能力,也因此函数可被作为任意其他类型对象来对待。

当我们说函数是第一类对象(一等公民)的时候,就是说函数也能实现对象的全部功能。

函数也是对象

JS 里,一切皆是对象,函数也不例外,废话不多说,直接测试一下,

「前端每日一问(19)」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     // 赋值给其他对象的属性
  • 函数可以作为函数的入参和出参,这是JS 为何有闭包的一个重要原因。
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 ,最后存储下来的只有一个,如下图,

「前端每日一问(19)」JS 中函数为什么被称为一等公民?

这种写法可以用于管理事件发生后需要调用的回调函数集合,已经存在于集合中的函数就不要再存进去了,提高性能。

自记忆函数

通过给函数添加属性来记住一些计算结果,之后再调用的时候就可以不用重新计算了,提高性能,以计算素数为例,

function isPrime (value) {
  if (!isPrime.cache) {
    isPrime.cache = {}   // 给函数添加一个 cache 来记住计算结果
  }
  if (isPrime.cache[value] !== undefined) {
    console.log(`缓存里有${value},直接返回`)
    return isPrime.cache[value]  // 如果有值就直接返回
  }
  let prime = value > 1    // 计算
  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)

「前端每日一问(19)」JS 中函数为什么被称为一等公民?

计算素数只是简单的计算,但如果用于处理复杂的计算,比如动画中的计算、搜索不经常变化的数据、耗时的数学运算等,对性能的提升无疑是巨大的。

小结

给函数添加属性的写法有利有弊:

  • 好处是能把属于这个函数的功能集中在一起;
  • 坏处是纯粹主义者会认为逻辑混合太多,函数应该只需要把一件事做好 仁者见仁,智者见智,纯粹的函数式编程有人做大量实践,给函数添加属性也有人做大量实践,比如 React 源码中的 FunctionComponent,也在函数上定义了一大堆属性呢。

「前端每日一问(19)」JS 中函数为什么被称为一等公民?

对于我们普通开发者而言,平时开发中能用就用,即使用不到,了解一下,开拓视野也挺好的。

结尾

如果我的文章对你有帮助,你的👍就是对我的最大支持^_^

我是阿林,输出洞见技术,再会!

上一篇:

「前端每日一问(18)」JS 中伪数组怎么转成数组

下一篇:

「前端每日一问(20)」说一下 JS 中的作用域、作用域链和词法作用域

转载自:https://juejin.cn/post/7075089473402306597
评论
请登录