1. 作用域的作用
-
提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
-
JS
没有块级作用域(ES6之前)
2. 全局作用域
- 使用var声明的变量,会挂载在window上,属于全局变量
- 不声明直接赋值的变量,也会挂载在window上
- var声明的变量和function声明的变量会提升
3. 函数作用域(局部作用域)
- 函数内部可以访问函数外部的变量
- 函数内部的变量只能当前函数,和当前函数内部的函数访问,包括形参
- 函数所在的作用域层,是属于声明时所在的,而不是调用时所在的
- 函数内部使用var声明变量,也会提升,提升到当前函数顶部
- 不声明直接赋值的变量,在函数外部也可以访问,相等于直接挂载在window上,但是它不会进入预解析
4. 全部变量和局部变量的区别
- 全局变量:在赋值之后的任何一个地方都可以使用,只有当页面关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当函数执行时才会存在,函数执行结束后就会被销毁,因此更节省内存空间
5. 作用域链
- 只要是代码,就至少会有一个作用域
- 函数内部又会存在函数作用域
- 如果函数作用域中还存在函数的话,又会存在新的作用域
- 内部可以访问外部的这种机制,更深层的作用域也可以访问外层的数据,这种链式的查找就称为作用域链
- 作用域链会采取就近原则,找到最近的变量
6. 预解析
-
预解析也叫变量提升或函数提升
-
JS
代码是由浏览器中的JS
解析器来执行的。JS
解析器在运行JS
代码的时候分为两步:预解析和代码执行。- 预解析:在当前作用域下,
JS
代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。这个预解析扫是在全部代码中扫的,如果函数没有调用它就不会扫,判断语句中即使为false也可以扫的到 - 代码执行: 从上到下执行
JS
语句。 - 特殊情况:在if语句中函数体也会声明,打印window在window上也可以看到,但是要是想访问的时候值却为undefined,这是一种特殊情况,并不符合预解析的规则
- 预解析:在当前作用域下,
// 1.全局扫,可以扫到else语句中
if (b === undefined) {
var a = 10
} else {
var b = 20
}
console.log(a); // 10
console.log(b); // undefined
// 2.函数没有执行,即使d可以添加到全局也不行
function c(){
d = 10
}
if(d === undefined){
console.log(1); // d is not defined
}
// 3.在if中,即使function可以提升但是获取的时候也为undefined
console.log(window); // 这里查看window时,e ==> f e()、f ==> undefined
// 为真把函数体提升了,但是获取还是为undefined
// 为假也提升了,但是是直接提升为undefined
console.log(e); // undefined
console.log(f); // undefined
if (true) {
function e() {
console.log(1);
}
} else {
function f() {
console.log(2);
}
}
console.log(e); // ƒ e() {console.log(1);}
console.log(f); // undefined
7. 预解析规则
-
全局里预编译:
- 创建
GO
对象 - 变量声明(var),将变量作为
GO
属性名,值为undefined - 在全局里找函数声明,将值赋予函数体
- 创建
-
函数体系里预编译:
- 创建
AO
对象 - 找形参和变量声明(var),将变量和形参作为
AO
属性名,值为undefined - 将形参和实参统一
- 在函数体里找函数声明,将值赋予函数体
- 创建