2018-03-12 00:31:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 前言
|
|
|
|
|
|
|
|
|
|
面试问题:
|
|
|
|
|
|
|
|
|
|
- 说一下对变量提升的理解
|
|
|
|
|
|
|
|
|
|
- 说明this的几种不同的使用场景
|
|
|
|
|
|
|
|
|
|
- 创建10个`<a>`标签,点击的时候弹出来对应的序号
|
|
|
|
|
|
|
|
|
|
- 如何理解作用域
|
|
|
|
|
|
|
|
|
|
- 实际开发中闭包的应用
|
|
|
|
|
|
|
|
|
|
涉及到的知识点:
|
|
|
|
|
|
|
|
|
|
- 执行上下文
|
|
|
|
|
|
|
|
|
|
- this
|
|
|
|
|
|
|
|
|
|
- 作用域
|
|
|
|
|
|
|
|
|
|
- 作用域链
|
|
|
|
|
|
|
|
|
|
- 闭包
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 执行上下文
|
|
|
|
|
|
|
|
|
|
执行上下文主要有两种情况:
|
|
|
|
|
|
|
|
|
|
- 全局代码: 一段`<script>`标签里,有一个全局的执行上下文。所做的事情是:变量定义、函数声明
|
|
|
|
|
|
|
|
|
|
- 函数代码:每个函数里有一个上下文。所做的事情是:变量定义、函数声明、this、arguments
|
|
|
|
|
|
|
|
|
|
PS:注意“函数声明”和“函数表达式”的区别。
|
|
|
|
|
|
|
|
|
|
先说全局的上下文:在执行代码之前,会先把所有的变量定义和函数声明拿出来(先拿出来放着,不急着赋值)。
|
|
|
|
|
|
2018-03-12 02:11:55 +00:00
|
|
|
|
![](http://img.smyhvae.com/20180311_1100.png)
|
2018-03-12 00:31:42 +00:00
|
|
|
|
|
|
|
|
|
## this
|
|
|
|
|
|
|
|
|
|
this指的是,**调用函数的那个对象**。
|
|
|
|
|
|
|
|
|
|
需要特别提醒的是:this的指向在函数定义时无法确认,只有函数执行时才能确定。
|
|
|
|
|
|
2018-03-12 02:11:55 +00:00
|
|
|
|
![](http://img.smyhvae.com/20180311_1117.png)
|
2018-03-12 00:31:42 +00:00
|
|
|
|
|
|
|
|
|
this的几种场景:
|
|
|
|
|
|
|
|
|
|
- 1、作为构造函数执行
|
|
|
|
|
|
|
|
|
|
例如:
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
function Foo(name) {
|
|
|
|
|
//this = {};
|
|
|
|
|
this.name = name;
|
|
|
|
|
//return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var foo = new Foo();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- 2、作为对象属性执行
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var obj = {
|
|
|
|
|
name: 'A',
|
|
|
|
|
printName: function () {
|
|
|
|
|
console.log(this.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj.printName();
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 3、作为普通函数执行
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
function fn() {
|
|
|
|
|
console.log(this); //this === window
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 4、call apply bind
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 作用域和作用域链
|
|
|
|
|
|
|
|
|
|
### 作用域
|
|
|
|
|
|
|
|
|
|
- **没有块级作用域**。
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
if (true) {
|
|
|
|
|
var name = 'smyhvae';
|
|
|
|
|
}
|
|
|
|
|
console.log(name);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
上方代码中,并不会报错,因为:虽然 name 是在块里面定义的,但是 name 是全局变量。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 只有全局作用域和函数作用域。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 作用域链
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
外部函数定义的变量可以被内部函数所使用,反之则不行。
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<title>Title</title>
|
|
|
|
|
<script>
|
|
|
|
|
//只要是函数就可以创造作用域
|
|
|
|
|
//函数中又可以再创建函数
|
|
|
|
|
//函数内部的作用域可以访问函数外部的作用域
|
|
|
|
|
//如果有多个函数嵌套,那么就会构成一个链式访问结构,这就是作用域链
|
|
|
|
|
|
|
|
|
|
//f1--->全局
|
|
|
|
|
function f1(){
|
|
|
|
|
//f2--->f1--->全局
|
|
|
|
|
function f2(){
|
|
|
|
|
//f3---->f2--->f1--->全局
|
|
|
|
|
function f3(){
|
|
|
|
|
}
|
|
|
|
|
//f4--->f2--->f1---->全局
|
|
|
|
|
function f4(){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//f5--->f1---->全局
|
|
|
|
|
function f5(){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 闭包
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
闭包就是能够读取其他函数内部变量的函数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|