Skip to content

函数 ​

2022-11-10 17:46:51

函数声明和函数表达式 ​

js 中定义函数主要两种方式,第一种是通过 function 来声明一个函数,第二种是通过变量的方式来接受一个函数。

在使用上是有一点点区别的

ts
// 没问题
foo()
function foo() {
  console.log('foo')
}

如上,我们通过 function 来声明一个函数时,js 引擎会在代码之前先读取函数声明,并在执行上下文中生成函数定义,即使函数定义出现在调用它们的代码之后,引擎也会把函数声明提升到顶部,所以我们这里调用函数不会报错

ts
// 报错
foo()
const foo = function () {
  console.log('foo')
}

而函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义。

函数的 length ​

每个函数都是对象,因此都有属性和方法,每个函数都有两个属性,prototype 和 length

length 属性保存函数定义的命名参数的个数

ts
function a(name) {
  console.log(name)
}
function b(num1, num2) {
  return num1 + num2
}
function c() {
  console.log('hi')
}
console.log(a.length) // 1
console.log(b.length) // 2
console.log(c.length) // 0

箭头函数和普通函数的区别 ​

先来看一下 MDN上对箭头函数的描述

引入箭头函数有两个方面的作用:更简短的函数并且不绑定 this

箭头函数不能作为构造函数使用 ​

先了解一下 new 操作符都做了什么

  • 创建一个对象
  • 把函数中的 this 指向该对象
  • 执行构造函数中的语句
  • 返回该对象实例

但是因为箭头函数没有自己的 this,所以箭头函数不能用作构造函数,或者说构造函数不能定义为箭头函数,否则在 new 时会报错

箭头函数没有自己的 this ​

箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this,并且箭头函数中 this 的指向在它被定义的时候就已经确定了,之后永远不会改变

js
const person = 'zhangsan'

// 普通函数
function fun1() {
  console.log(this.person)
}

// 箭头函数
const fun2 = () => {
  console.log(this.person)
}

fun1.call({ person: 'lisi' }) // zhangsan
fun2.call({ person: 'lisi' }) // lisi

解耦的小技巧 ​

当我们递归执行一段代码时,不可避免的会重复调用函数,那么我们函数中会耦合一些内容,比如这里我们写了一个阶乘的函数,递归调用。

ts
function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * factorial(num - 1)
  }
}

我们可以通过函数内 arguments 的 callee 属性来进行解耦,callee 属性是一个指向 arguments 对象所在函数的指针,那么我们的代码就可以这样改一下

ts
function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * arguments.callee(num - 1)
  }
}

这样改完后,不管函数名怎么改,都不会影响这里递归的调用,避免函数可能被赋值为其他名称后递归调用失败

Released under the MIT License.