1、默认参数用法
函数默认参数示例:
//es6写法
function test(a=1,b=2) {
console.log(a,b)
}
test(3) //3,2
test(3,4) //3,4
test() //1,2
//es5写法
function test(a,b) {
var a = a || 1;
var b = b || 2;
console.log(a,b)
}
函数参数的默认值可以与解构赋值结合使用,此处的学习容易混乱,主要还是学以致用,尽量在代码中多用自己学习到的新东西(谨代表我个人观点),下面是es6官网给出的两个例子,思考两种方式有什么不同:
// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]
// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]
// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
个人理解:第一种方式是解构赋值默认值与函数参数默认值的结合,如果函数没有传入任何参数,函数的参数默认值就是一个空对象,接下来才是解构赋值默认值,如果传入参数,则会按照传入的参数的属性名称查找传入参数是否具有同名属性,如果具有,覆盖默认值,否则,继续使用默认值,如果属性的值为undefined,则采用默认值;第二种方式,只使用了函数参数默认值,没有解构赋值的默认值,没有传入参数的时候,相当于参数是{x:0,y:0},然后在对这个参数进行解构,如果传入了参数,就使用传入的参数,就会忽略函数默认值。
此外,还要注意默认参数的位置必须是最后一个,如果不是,则不能省略默认参数的传值。
2、默认参数作用域
先看个案例:
var x = 1;
function test (x, y = x) {
console.log(y)
}
test(2) // 2
只要为函数设置了默认参数,函数进行声明初始化时,参数就会形成一个单独的作用域,初始化结束,作用域就会消失。所以最终的输出结果是2。
书中还有两个例子,我觉得挺好的,就直接搬过来了,如下:
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
个人理解:第一段代码中,由于为参数y设置了函数的默认参数,所以,在函数进行声明初始化时,参数x,y是在一个单独的作用域里面,参数y里面的x是指向参数x,而在foo函数作用域内,又重新声明了一个局部变量x,这个局部变量x与参数x,y的作用域并不是同一个作用域,也就是说,参数x只有在y的默认参数里才能访问到,当console的时候,永远找的是foo函数作用域内的变量x,也就是3;第二段代码中,只去掉了一个var声明,此时x=3的过程是,先在当前作用域中找有没有声明过这个x,参数里有声明变量x,所以,没有var的x实际上就是指向参数x,紧接着在后面执行了y(),相当于x=3;x=2;后一个覆盖前一个,如果调换下位置,y();x=3 ,此时输出应该是3。
下面有一段自己的代码:
var x = 1;
function foo(x, y = function () { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo(undefined, function () { x = 2; }) //3
x //2
此时,函数传入的实参实际上是在全局作用域中,并且赋值给了变量y(变量y持有对全局作用域中实参的一个引用),也就是说,此时的function() {x=2}实际上是在全局作用域中找到声明的变量x,并且将2赋值给x,而foo函数作用域内的x=3,仍然指向参数x,内部作用域有声明的x,自然不会去到外部作用域找了,自然打印出3。