函数的扩展
函数参数默认值
- 🧊ES6之前指定默认值的方法有:
- 使用
||
表达式,当y未赋值时,y的值为右值;然y为假值时,y的值会被覆盖
- 使用
- 🧊ES6开始函数参数可使用默认值形式:
fn(a, b = a)
,注意:- 参数变量是默认声明的,在函数体内不能使用let、const进行重新声明
- 若有参数使用了默认值,则所有的参数不可重名
- 应用:
- 指定不可省略该参数,省略则抛出错误,举例:🍡
- 将参数指定为undefined,表明该参数可省略
- 🧊参数默认值可和解构赋值默认值一起使用:
fn({a, b = a} = {a = 1, b = 2})
,注意:- 在无参数默认值
{a = 1, b = 2}
只有在传入对象时,对象内的变量才会通过解构赋值生成,否则报错 - 若未传入参数,则参数默认值与解构默认值同时生效;若传入参数,则传入参数的同时,解构默认值仅在参数对象无该变量时生效
- 参数默认值需在参数的末尾,否则无法省略,除非显式赋值成
undefined
- 在无参数默认值
- 🧊函数的length属性值为:
- 函数参数个数 - 有默认值的参数个数 - rest参数;若默认值参数后面有非默认值参数,会自动忽略这些参数
- 🧊作用域:若设置了参数默认值,在函数进行声明初始化时,参数会形成一个单独的作用域,在初始化结束后,作用域自动消失,注意:
- 未设置默认值,无此现象
fn(x = x)
,调用时无参,调用时所在作用域及其上级作用域无x
变量时,将会报错- 举例:🍋
javascript
// 🍡
function throwIfMissing () {
throw new Error('缺少参数')
}
function foo (mustBeProvided = throwIfMissing()) {
// .....
}
foo() // Error: 缺少参数
// 🍋
var a = 1
function foo (a, y = function () { a = 2 }) {
var a = 3
y()
console.log(a)
}
foo() // 3
a // 1
var b = 1
function bar (b, y = function () { b = 2 }) {
b = 3
y()
console.log(b)
}
bar() // 2
b // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
rest参数
- 🥣定义:rest参数获取函数的多余参数,形式为
fn(...arr)
,- 获取时,将所有的参数放入到一个数组arr中,这样就不需arguments参数了
- arguments为一个类数组形式,在使用数组方法时,必须使用
Array.prototype.slice.call(arguments)
换成数组 - rest参数后面不能有其他参数
严格模式
- ES5开始,函数内部可使用严格模式
- ES6中,若函数参数有默认值,解构赋值,rest参数时,不能使用严格模式,否则会报错,因为:
- 函数内部严格模式适用于函数体和函数参数列表
- 函数参数先于函数体执行,但只有执行完函数体后,才知道是否应用严格模式
- 解决方法:
- 使用全局严格模式
- 将函数放在无参的IIFE的return中
函数的name属性
- name属性返回function后面跟的名字,注意:
- function后面未跟名字,则返回函数表达式的名字,ES5返回空串
(new Function).name
返回anonymous- 调用了bind的函数,会返回包含一个前缀为bound的值
箭头函数
- 若箭头函数返回一个对象,且只有一条语句时,需使用括号括起来
- 箭头函数的this是指定义时的对象,而非运行时的对象(普通函数)
- 箭头函数不可当作构造函数使用
- 箭头函数无arguments对象、super、new.target
- 箭头函数不能使用yield
- 不适用的场合:
- 定义对象的方法,且该方法包含this时(全局作用域)
- 动态使用this的时候,比如点击事件绑定的btn等等
- 当函数体过于复杂时,需使用普通函数,便于可读
尾调用优化
- 尾调用:函数的最后一步调用的
直接是一个函数
,也可以说返回的直接是一个函数才算 - 调用帧:函数调用会在内存中形成一个记录,保存调用位置和内部变量等信息,所有的调用帧连起来,会形成一个调用栈
- 尾调用优化:尾调用函数只有在不会用到外层函数的变量时,内层函数的调用帧才会取代外层函数的调用帧,进行优化,节省内存(仅Safira支持)
- 仅在严格模式中有效,因为正常模式下,arguments,caller会跟踪调用栈
- 尾递归:在函数的最后一步调用自身,由于只存在一个调用帧,不会发生栈溢出错误
- 柯里化:多参数函数形式转为单参数的形式
其他
- ES2017允许函数的参数有尾逗号,这样在增加/删除时更加方便,同时也使版本管理更加方便知道修改了什么,而不是存在一些无意义的内容
- ES2019中,toString方法会返回函数代码本身(原始代码),包括注释和空格
- ES2019允许catch在不需要参数时,可省略参数,直接
catch {}
的形式