写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。Github地址。
作用域
作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码中变量和其他资源的可见性。单纯看这两句话可能并不好理解,来看个🌰:
function fn() {
var a = '内部变量a';
}
fn();
console.log(a); // Uncaught ReferenceError: a is not defined
1
2
3
4
5
2
3
4
5
从上面的🌰中可以体会到作用域的概念,变量a在全局作用域没有声明,所以在全局作用域访问会报错。
- 理解
- 作用域就是一块"地盘",一个代码段所在的区域
- 它是静态的(相对于执行上下文对象),在编写代码时就确定了
- 执行上下文对象是函数调用时产生的,而作用域是在函数定义时就确定了的,多次调用函数也不会产生多个作用域。
- 分类
- 全局作用域
- 函数作用域
- 没有块级作用域(ES6有,let和const可以定义块级作用域)
- 作用
- 隔离变量,不同作用域下同名变量不会有冲突
// 没有块级作用域
if (true) {
var a = 2;
}
console.log(a); // 2
var b = 3;
function bar() {
var c = 4;
console.log('bar', c);
}
console.log('global', b);
bar();
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
无块级作用域:在花括号中定义变量和在花括号外面定义变量是一样。
function c() {
var b = 1;
function a() {
console.log(b); // undefined
var b = 2;
console.log(b); // 2
}
a();
console.log(b); // 1
}
c();
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
小结
- js没有块级作用域(ES6以前);
- 只有全局和函数作用域;
- 内部作用域可以访问外部作用域,外部的不能访问内部;
- 优先在内部作用域查找,找不到的话沿着作用域链向上查找。
作用域与执行上下文区别
- 区别1:产生时机不同
- 全局作用域之外,每个函数都会创建自己得作用域,作用域在函数定义的时候就已经确定了,而不是在函数调用的时候。
- 全局执行上下文是在全局作用域确定之后,js代码执行之前创建
- 函数执行上下文是在函数调用时,函数体代码执行之前创建
- 区别2:
- 作用域是静态的,只要函数定义好了就一直存在,且不会再变化
- 执行上下文是动态的,调用函数时创建,函数调用结束时就会自动释放
- 联系:
- 执行上下文是从属于所在的作用域
- 全局执行上下文==>对应全局作用域
- 函数执行上下文==>对应函数作用域
作用域链
创建作用域链:在代码在一个执行上下文中执行时,会创建变量对象的一个作用域链。
- 理解
- 多个上下级关系的作用域形成的链,它的作用是:保证对执行环境中有访问权限的变量和函数进行有序访问,方向是从内向外的(内部作用域可以访问外部作用域,反之则不行)。
- 查找变量时就是沿着作用域链来查找的。
- 变量查找规则
- 在当前作用域下的执行上下文的变量对象中查找对应的属性,如果有则直接返回,否则进入步骤2
- 在上一级作用域的执行上下文的变量对象中查找对应的属性,如果有直接返回,否则进入步骤3
- 再次执行步骤2的查找操作,直到全局作用域的变量对象(即window对象),如果还没有找到就抛出找不到的异常。
举个🌰:
var a = 1;
function fn() {
var b = 2;
function bar() {
var c = 3;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // Uncaught ReferenceError: d is not defined
}
bar();
}
fn();
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
面试题
var x = 10;
function fn() {
console.log(x); // 10
}
function show(fn) {
var x = 20;
fn();
}
show(fn);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
自由变量:当前作用域中没有定义的变量。当前作用域没有,就去父级作用域中找。
特别注意:父级作用域是函数定义时的作用域,而不是函数调用的时候的作用域。
在fn函数中,取自由变量x的值时,要到哪个作用域中取?到创建fn函数的那个作用域(这里是全局作用域)中取,无论fn函数将在哪里调用。
var fn = function() {
console.log(fn);
}
fn();
var obj = {
fn2: function() {
console.log(fn2); // 报错 Uncaught ReferenceError: fn2 is not defined
// 正确写法
// console.log(this.fn2);
}
};
obj.fn2();
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
首先在当前作用域查找fn2没有找到,继续沿着作用域链向上查找,全局作用域中也没有找,所以抛出找不到的异常。
需要注意的小细节
去掉var的局部变量
var name = 'wangwu';
function setName() {
name = 'lisi'; // 去掉var变成了全局变量,会覆盖全局中的name
}
setName();
console.log(name); // lisi
1
2
3
4
5
6
2
3
4
5
6
形参也是局部变量
var name = 'wangwu';
function setName(name) { // 形参也是局部变量
console.log(name);
}
setName('lisi'); // lisi
console.log(name); // wangwu
1
2
3
4
5
6
2
3
4
5
6
参考文档
阅读量: