函数
2022-11-10 17:46:51
函数声明和函数表达式
js 中定义函数主要两种方式,第一种是通过 function 来声明一个函数,第二种是通过变量的方式来接受一个函数。
在使用上是有一点点区别的
ts
// 没问题
foo()
function foo() {
console.log('foo')
}
1
2
3
4
5
2
3
4
5
如上,我们通过 function 来声明一个函数时,js 引擎会在代码之前先读取函数声明,并在执行上下文中生成函数定义,即使函数定义出现在调用它们的代码之后,引擎也会把函数声明提升到顶部,所以我们这里调用函数不会报错
ts
// 报错
foo()
const foo = function () {
console.log('foo')
}
1
2
3
4
5
2
3
4
5
而函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义。
函数的 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
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
箭头函数和普通函数的区别
先来看一下 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
解耦的小技巧
当我们递归执行一段代码时,不可避免的会重复调用函数,那么我们函数中会耦合一些内容,比如这里我们写了一个阶乘的函数,递归调用。
ts
function factorial(num) {
if (num <= 1) {
return 1
} else {
return num * factorial(num - 1)
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
我们可以通过函数内 arguments 的 callee
属性来进行解耦,callee 属性是一个指向 arguments 对象所在函数的指针,那么我们的代码就可以这样改一下
ts
function factorial(num) {
if (num <= 1) {
return 1
} else {
return num * arguments.callee(num - 1)
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
这样改完后,不管函数名怎么改,都不会影响这里递归的调用,避免函数可能被赋值为其他名称后递归调用失败