1. 函数变量的作用域链
- 先在当前函数作用域内部查找是否含有变量,如果没有,就去上一级作用域中查找
- 举个栗子:
let x = 3;
let y = 10;
function test1() {
let x = 5;
function test2() {
console.log(x, y);
}
return test2();
}
test1() //输出结果为5,10
- 对上述例子的图解
2. 理解了函数作用域链之后、观察有默认形参的作用域链有什么不同
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。 —摘自阮一峰<es6>
- 引例1
let y = 'out';
function test(x, y = 'world') {
var y = 'hello'
console.log(y);
console.log(x);
return [x, y]
}
console.log(y); //out
console.log(test('hello')); //['hello','hello']
- 引例1图解
- 引例2:提前调用报错
var x = 1;
function foo(x = x) {
// ...
}
foo() //报错:Cannot access 'x' before initialization
-
引例2图解
-
引例3
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
- 引例3图解
- 引例4:对引例3的进一步分析
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
大家可以自己画以下图,因为在foo()的内容作用域中没有var x,那么就在当前作用域中找不到x,就去上一级找,也就是去foo()的形参作用域中找,有x啊,而且被赋值为了2,所以打印输出2.
- 最后我们来分析引例1的return[x,y]为什么输出[‘hello’,‘hello’]
let y = 'out';
function test(x, y = 'world') {
var y = 'hello'
console.log(y);
console.log(x);
return [x, y]
}
console.log(y); //out
console.log(test('hello')); //['hello','hello']
- 图解:
观察指向哦,而且调用的时候·
console.log(test('hello'));
,所以x被赋值为hello,最后输出【‘hello’,‘hello’】
- js函数参数和函数体内的再次声明不一样,原因是啥?
形参内部是let声明的吗?上面的例子彻底懂了之后,这两个迷惑的问题就可以迎刃而解。