前言:ES6中规定函数参数可以使用默认值,其参数可与解构赋值的默认值结合使用,且函数此时的length属性返回的是无指定默认值参数的个数
注意: 一旦设置参数默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
//题一
let x = 1;
function f(y) {//这个参数y和下面函数内部是属于同一个作用域的(因为此时函数参数没有默认值)
let x = 2; //这个x在函数作用域内,和最外层的x=1不是同一个作用域,可以再次声明
y=x;
console.log(y);
}
f();//2
//题二
let x = 1;
function f(y = x) {//参数`y = x`形成一个单独的作用域
let x = 2; //和上面的x不是同一个作用域,所以可以重复声明
console.log(y);
}
f() // 1
//题三
//y和外面的x值是一样的,在函数内部没有重新给y赋值!!!
let x;
function f(y = x) {//参数`y = x`形成一个单独的作用域
let x = 2;
console.log(y);
}
f() // undefined
//注意在同一作用域里面千万不能重复声明
let x = 99;
let x = 100;//Identifier 'x' has already been declared
上面代码中,函数f
调用时,参数y = x
形成一个单独的作用域。这个作用域里面,变量x
本身没有定义,所以指向外层的全局变量x
。函数调用时,函数体内部的局部变量x
影响不到默认值变量x
。
下面是一个更复杂的例子。
//我终于明白了,哈哈哈
var x = 1; //第一层
//在函数参数里面,都默认声明,属于第二层作用域
function foo(x, y = function() { x = 2; console.log(x);}/*第二层*/) {
var x = 3; //在此又声明一次,属于第三层作用域
y(); //2,但是是在第二个作用域里面
console.log(x); //是第三个作用域里面的值 3
}
foo() // 2 3
console.log(x) // 1
上面代码中,函数foo
的参数形成一个单独作用域。这个作用域里面,首先声明了变量x
,然后声明了变量y
,y
的默认值是一个匿名函数。这个匿名函数内部的变量x
,指向同一个作用域的第一个参数x
。函数foo
内部又声明了一个内部变量x
,该变量与第一个参数x
由于不是同一个作用域,所以不是同一个变量,因此执行y
后,内部变量x
和外部全局变量x
的值都没变。
如果将var x = 3
的var
去除,函数foo
的内部变量x
就指向第一个参数x
,与匿名函数内部的x
是一致的,所以最后输出的就是2
,而外层的全局变量x
依然不受影响。
var x = 1; //第一层
function foo(x, y = function() { x = 2;/*第二层*/ }) {
x = 3; //没有声明,属于上一层作用域,即属于第二层
console.log(x); //此时x值为3
y(); //实例化后,x值变为2
console.log(x); //2
}
foo(); //3 2
console.log(x) // 1
函数参数中有无的影响:
//第一种情况:函数中有参数x
var x = 1; //第一层
function foo(x) { //其实x在此处是声明了的,所以x是局部变量
x = 3; //局部变量 function内部是一个单独的作用域,这个值不影响全局
console.log(x);
}
foo() // 3
console.log(x); //1
//第二种情况:函数中没有参数x
var x = 1; //第一层
function foo() {
x = 3; //此时x才是真正的全局变量
console.log(x);
}
console.log(x); //1 因为函数没有实例化,所以x还是原来的值
foo(); // 3
console.log(x); //3 实例化后,x就是改变过后的值