函数参数的默认值
- 基本用法
- ES6之前 由于不能直接为函数的参数指定默认值 所以只能采用一些变通的方法
function log(x, y) {
y = y || 'world'
console.log(x, y)
}
- 上面代码问题是:如果参数y赋值了 但是对应的布尔值为false 则该赋值不起作用 例如
参数y等于空字符 结果被改为默认值
- 参数变量x, y是默认声明的 在函数体中不能用let 或 const再次声明
- 与解构赋值默认值结合
function foo({x, y = 5}) {
console.log(x, y)
}
- 只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值而生成
- 如果函数foo调用时参数不是一个对象,变量x和y变量就不会生成,从而报错。
- 只有参数对象没有y属性时,y的默认值才会生效。
-
参数默认值的位置
- 定义了默认值的参数应该是函数的尾参数。因为这样比较容易快拿出来到底省略了哪些参数。
- 如果带默认值的参数在参数整体非末尾位置,则没有办法只省略该参数而不省略其后的参数。除非显示输入undefined,null没有这个效果。
-
length属性
- 指定了默认值以后。函数的length属性将返回没有指定默认值的参数个数
- 如果都指定了默认值,length属性将失真。
- 如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数。
-
作用域
- 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域context,等到初始化结束时,这个作用域就会消失。这种语法行为在不设置参数默认值时是不会出现的。
let x = 1
function f(x, y = x) ...
- 参数y的默认值等于变量x,调用函数f时,参数会形成一个单独的作用域。在这个作用域里面,默认值变量x指定第一个参数x,而不是全局变量x。
let x = 1
function f(y = x) {
let x =2
}
- 调用函数f时,参数y = x形成一个单独的作用域。在这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x。并且函数体内部的局部变量x影响不到默认值变量x。同时如果全局变量x不存在,就会报错。
function f(x = x) ...
- 参数x = x形成ige单独作用域 实际执行的是let x = x 由于暂时性死区 执行时会报错。
- 当参数的默认值是一个函数时:
function bar(func = x => foo) ...
- 与上面规则相同
-
rest参数
- 用于获取函数的多余参数
...变量名
- rest参数搭配的变量是一个数组 将多余参数放入其中 所以数组特有的方法都可以用于这个变量
- 函数的length属性不包括rest参数
-
严格模式
- ES7规定只要函数参数使用了默认值、解构赋值或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则就会拨错。
- 这样规定的原因是函数内部的严格模式同时是英语函数体和函数参数。但是函数执行时,先执行函数参数,然后再执行函数体。但是只有从函数体之中才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。
-
name属性
- 函数的name属性返回该甘薯的函数名
- 将匿名函数赋值给一个变量 name值为变量的名字(ES6) ES5为空字符串
const bar = function baz() { } bar.name // ”baz“
- Function构造函数返回的函数实例 name的属性值为anonymous
- bind返回的函数 name属性值会加上bound前缀
-
箭头函数
- 箭头函数可以让setTimeout里面的this绑定定义时所在的作用域。
- this指向的固定化并不是箭头函数内部有绑定this的机制,实际原因时箭头函数根本没有自己的this,导致内部this就是外层代码块的this,正因为没有this,所以不能用作构造函数(new的时候要绑定this)。
- 由于箭头函数没有自己的this,当然也就不能用call()、apply()、bind()这些方法去改变this的指向。
-
尾调用
- 尾调用(Tail Call) 是函数式编程的一个重要概念,是指某个函数的最后一步是调用另一个函数。
- 尾调用不一定出现在函数尾部,只要是最后一步操作即可(return)。
- 尾调用优化:
- 尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧(保存调用位置和内部变量等信息),因为调用位置、内部变量等信息都不会再用到了,直接用内层函数的调用帧取代外层函数的即可。
-
尾递归
- 尾调用自身为尾递归。
笔记内容整理来自阮一峰老师的《ES6标准入门》