JavaScript-作用域与闭包

2020/7/5 JavaScript
// 执行上下文
1. this
2. 变量环境
  1. var
3. 词法环境
  1. let
  2. const
4. 外部环境
5. 变量查找顺序
  1. 词法环境 ===> 变量环境
----------------------------------------------------------------------------------------------
// 作用域
1. 作用域有全局作用域和局部作用域之分
2. 作用域链是用来查询变量的(由内到外)
3. es6新增的块级作用域
4. eval() 函数会把传入的参数当做js代码执行, 不管是不是js代码
5. 词法作用域:也称为静态作用域。这是最普遍的一种作用域模型,也是我们学习的重点
6. 动态作用域:相对“冷门”,但确实有一些语言采纳的是动态作用域,如:Bash 脚本、Perl 等
----------------------------------------------------------------------------------------------
// 垃圾回收机制
1. 引用计数:
    在引用计数法的机制下,内存中的每一个值都会对应一个引用计数。当垃圾收集器感知到某个值的引用计数为 0 时
    就判断它 “没用” 了,随即这块内存就会被释放。
    引用计数解决不了循环引用的问题,即 A 引用了 BB 引用了 A,就造成 AB 都无法被回收
2. 标记清除: // 主流
    标记阶段: 垃圾收集器会先找到根对象,在浏览器里,根对象是 Window;在 Node 里,根对象是 Global。从根对象出发
              垃圾收集器会扫描所有可以通过根对象触及的变量,这些对象会被标记为 “可抵达”。
    清除阶段: 没有被标记为 “可抵达” 的变量,就会被认为是不需要的变量,这波变量会被清除
----------------------------------------------------------------------------------------------
// js解析机制(1、2是预解析)
1. 所有var都赋值为undefined,参数当做局部变量处理,函数提前声明
2. 变量与函数冲突则保留函数,函数与函数冲突,保留后面的
3. 逐行解读
4. 旧版本火狐不能对iffor这种代码块中的函数进行预解析,多个script是分开解析的
----------------------------------------------------------------------------------------------
// 内存问题
1. 离开作用域的值被标记为可回收,将在垃圾收集期间被删除
2. 标记清除是目前主流的垃圾收集算法
3. 标记清除就是给不用的值加标记,然后回收其内存
4. 引用计数算法可能因为循环引用的问题而得不到释放
5. 当变量不用的时候,可以手动解除它的引用(赋值为null)
----------------------------------------------------------------------------------------------
// 闭包
1. 函数作为返回值
2. 函数作为参数
3. 函数b在a内嵌套的,函数a需要返回b
4. 可用于读取函数内部变量,让变量保留在内存中
----------------------------------------------------------------------------------------------
// 自由变量
1. 一个变量在当前作用域没有定义,但被使用了
2. 所有自由变量的查找,是在函数或变量定义的地方,向上级作用域查找,不是在执行的地方
----------------------------------------------------------------------------------------------
// this 指向
1. node 环境函数的 this 默认指向 global,全局的 this 是个空对象
2. 浏览器环境函数的 this 和全局的 this 默认是 window
3. 使用 bind 函数改变 this 时,多次 bind,只会取第一次 bind 时的 this // :: 绑定符
----------------------------------------------------------------------------------------------
// this的使用场景
1. 作为普通函数
2. 使用call、apply、bind
3. 作为对象方法被调用
4.class方法中调用
5. 箭头函数
6. this 的取值是在函数执行时确认的,不是在函数定义时确认的 // 和自由变量查找相反
----------------------------------------------------------------------------------------------
// this 会 100% 指向 window:
1. 立即执行函数(IIFE2. setTimeout 中传入的函数
3. setInterval 中传入的函数
----------------------------------------------------------------------------------------------
// 普通函数this指向
1. 总是代表着它的直接调用者,如obj.fn,fn的this就是obj
2. 默认情况下没有直接调用者,this指向window
3. 严格模式下(设置了'use strict'),thisundefined
4. 当使用call、apply、bind绑定的,this指向绑定对象
----------------------------------------------------------------------------------------------
// 箭头函数this指向
1. 继承于父级执行上下文里的this,本身没有this
2. 即使是call、apply、bind方法也不能改变箭头函数的this指向
3. 简单对象(非函数)是没有执行上下文的
----------------------------------------------------------------------------------------------
// this案例演示
1. function hello() { console.log(this) }
hello函数是全局函数没有直接调用它的对象,没有严格模式所以指向window
2. function hello() { 'use strict' console.log(this) }
hello函数是全局函数没有直接调用它的对象,有严格模式所以指向undefined
3. const obj = {
  hello: function() {
    console.log(this) //obj
    setTimeout(function() {
      console.log(this) // window
    }, 1000)
  }
}
hello函数直接调用者是obj,所以第一个this指向obj,setTimeout是匿名函数没有直接调用者,也没有严格模式所以指向window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Last Updated: 2024/7/31 12:57:25
    飘向北方
    那吾克热-NW,尤长靖