Web/04-JavaScript基础/10-作用域.md
2019-12-10 22:39:08 +08:00

178 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

> 作用域、变量提升的知识点,面试时会经常遇到。
## 作用域Scope的概念
通俗来讲,作用域是一个变量或函数的作用范围。作用域在**函数定义**时,就已经确定了。
### 作用域的分类
在js中一共有两种作用域
- 全局作用域
- 函数作用域
### js 是函数级别作用域
js 是函数级别作用域:在内部作用域中可以访问到外部作用域的变量,在外部作用域中无法访问到内部作用域的变量。
代码举例:
```javascript
var a = 'aaa';
function foo() {
var b = 'bbb';
console.log(a); // 打印结果aaa。说明 内层作用域 可以访问 外层作用域 里的变量
}
foo();
console.log(b); // 报错Uncaught ReferenceError: b is not defined。说明 外层作用域 无法访问 内层作用域 里的变量
```
定义在全局作用域的变量,叫「全局变量」。
定义在函数作用域的变量,叫「局部变量」。
### 作用域的上下级关系
当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(**就近原则**)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错 ReferenceError。
在函数中要访问全局变量可以使用window对象。比如说全局作用域和函数作用域都定义了变量a如果想访问全局变量可以使用`window.a`
## 全局作用域
直接编写在script标签中的JS代码都在全局作用域。
- 全局作用域在页面打开时创建,在页面关闭时销毁。
- 在全局作用域中有一个全局对象window它代表的是一个浏览器的窗口由浏览器创建我们可以直接使用。
在全局作用域中:
- 创建的**变量**都会作为window对象的属性保存。比如在全局作用域内写 `var a = 100`,这里的 `a` 等价于 `window.a`
- 创建的**函数**都会作为window对象的方法保存。
全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到。
### 变量的声明提前(变量提升)
使用var关键字声明的变量 比如 `var a = 1`**会在所有的代码执行之前被声明**但是不会赋值但是如果声明变量时不是用var关键字比如直接写`a = 1`),则变量不会被声明提前。
举例1
```javascript
console.log(a);
var a = 123;
```
打印结果undefined。注意打印结果并没有报错而是 undefined说明变量 a 被提前声明了,只是尚未被赋值。
举例2
```javascript
console.log(a);
a = 123; //此时a相当于window.a
```
程序会报错:
![](http://img.smyhvae.com/20180314_2136.png)
举例3
```javascript
foo();
function foo() {
if (false) {
var i = 123;
}
console.log(i);
}
```
打印结果undefined。注意打印结果并没有报错而是 undefined。这个例子再次说明了变量 i 在函数执行前,就被提前声明了,只是尚未被赋值。
打印结果:
### 函数的声明提前
**函数声明**
使用`函数声明`的形式创建的函数`function foo(){}`**会被声明提前**。
也就是说,整个函数会在所有的代码执行之前就被**创建完成**。所以,在代码顺序里,我们可以先调用函数,再定义函数。
代码举例:
```javascript
fn1(); // 虽然 函数 fn1 的定义是在后面,但是因为被提前声明了, 所以此处可以调用函数
function fn1() {
console.log('我是函数 fn1');
}
```
**函数表达式**
使用`函数表达式`创建的函数`var foo = function(){}`**不会被声明提前**,所以不能在声明前调用。
很好理解因为此时foo被声明了这里是变量声明且为undefined并没有把 `function(){}` 赋值给 foo。
所以说,下面的例子,会报错:
![](http://img.smyhvae.com/20180314_2145.png)
## 函数作用域
**提醒1**:在函数作用域中,也有声明提前的特性:
- 函数中使用var关键字声明的变量会在函数中所有的代码执行之前被声明
- 函数中没有var声明的变量都是**全局变量**,而且并不会提前声明。
举例1
```javascript
var a = 1;
function foo() {
console.log(a);
a = 2; // 此处的a相当于window.a
}
foo();
console.log(a); //打印结果是2
```
上方代码中执行foo()后,打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined`
**提醒2**:定义形参就相当于在函数作用域中声明了变量。
```javascript
function fun6(e) { // 这个函数中,因为有了形参 e此时就相当于在函数内部的第一行代码里写了 var e;
console.log(e);
}
fun6(); //打印结果为 undefined
fun6(123);//打印结果为123
```
## 我的公众号
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**id`qianguyihao`)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
![](http://img.smyhvae.com/2016040102.jpg)