一,作用域
1.1 什么是作用域
概念:在某个上下文EC中创建函数时,除了开辟内存和赋值外,还要给当前的函数设置一个作用域属性[[scope]]。
特点:当前函数的作用域[[scope]] = 当前函数创建时候所在的上下文EC(xxx)
1.2 作用域分类
类型 | 说明 | 特点 |
全局作用域 | 在页面打开时创建、页面关闭时销毁 | 1.全局作用域只有一个全局对象window,其他均为window的属性和函数 2.不能访问函数作用域里面的变量 |
函数作用域 | 当函数执行时,会创建一个执行期上下文的内部对象。每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立的。当函数执行完毕,它所产生的执行期上下文会被销毁 | 1.函数中用var声明的变量、函数都会在函数内所有代码执行前被声明 2.函数中没用用var声明的变量,是全局变量,而且不会被提前声明 3.闭包在函数作用域中产生 |
块级作用域 | ES6引入,一个代码块{}中的作用域 | 1.使用ES6的let和const声明实现 |
模块作用域 | ES6引入,每个模块是一个作用域。通过导入、导出来实现模块间的调用 | 1,有CommonJs、AMD、CMD、UMD、ES6Module多种方案 2,CommonJs:主要用于服务端js(nodejs)模块化方案的规范,浏览器暂不支持,需要转换器来转换代码。他是同步加载的。主要关键字有:module、exports、require、global 3,AMD:主要用于浏览器端的js模块化方案的规范,实现它的库有require.js。他是异步加载的。主要关键字有:define、require 4,CMD:与AMD类似,也是用于客户端js的模块化方案规范,实现他的库有sea.js。也是异步加载。对于依赖的模块,它一开始就推崇就近依赖,延迟加载(reuqire.js是2.0以后才支持);AMD推崇前置依赖(第一时间将前面数据内的模块都加载完)主要关键字同AMD,同时也包含function、exports、module等 5,UMD:一种通用的模块规范。支持同步和异步,也可以支持服务端和客户端js。他是通过检测全局对象(如:global、window)来判断当前环境,并决定选择使用commonJS还是AMD、CMD规范来实现。 6,ES6 Module:在ES6语言的标准上实现了模块功能,使用比较简单,不需要引用额外的库。主要关键字是import和export关键字实现(import是只读关键字,类似于const,不能被赋值;export可以导出整个模块,还可以导出某一个单独的值),关键字必须用于模块的顶级 |
1.3 模块作用域的区别
1,ES6模块作用域export导出的是一个只读的值的引用,而commonJS导出的是一个值的拷贝(说明ES6中如果导入的模块中某个值变了,import的值也跟着改变)
2,ES6模块作用域export同时支持全局和局部导出,而commonJS的export module是导出整个模块
3,ES6的import在指定加载某个值时,不是加载的整个模块,这种加载方式又称为编译时加载
二,作用域链
2.1 什么是作用域链
作用域链scopeChain的形成:作用域链是在函数执行的时候形成的。他包括当前函数的作用域[[scope]]、当前执行的上下文EC,以此来建立的一个链式关系
概念:在查找一个变量的时候,先从当前 作用域scope/上下文EC 中查找,如果没有查找到,就会到上级 作用域scope/上下文EC 中查找,直到全局作用域/上下文EC(G),这样查找的过程形成的链条就是作用域链scopeChain
上级作用域:函数的上级作用域在哪创建的,它上级作用域就是谁(也就是当前上下文的上层上下文)
查找机制详解:
1,判断变量是否为私有。如果是私有的,直接操作自己的变量。
2,如果为非私有的,则按照scopeChain作用域链查找,在哪个上下文中找到,当前变量就属于谁。
3,......一直找到全局
4,如果全局也没有此变量,判断当前行动:
(1)获取变量:则系统会报错,当前变量没有定义
(2)赋值操作:相当于给一个全局变量赋值