作用域
概念:变量可以起作用的范围(区域)。
作用域又分为全局作用域和局部作用域。
之前说过变量可以起作用的范围,那肯定也有全局变量和局部变量。
全局作用域:
供所有代码执行的环境(整个script标签内部)或者一个独立的js文件中
全局变量:
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
全局变量在代码的任何位置都可以使用。
特殊情况, 再函数内不var声明的变量也是全局变量 (不建议使用)。
局部作用域:
在调用函数的时候会形成一个执行函数内代码的新环境。
局部变量:
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)。
局部变量只能在该函数内部使用。
配图理解:
<script>
var scope = 12; // 全局变量
function demo() {
var local = 1; // 局部变量
console.log(scope) // 12
console.log(local) // 1
}
console.log(scope) // 12
console.log(local) // 报错 local is not defined
</script>
上面的代码中可以看出scope是一个全局变量,local是一个局部变量。
如上图所说全局变量在任何地方可以访问到。在demo函数内输出是可以输出的。
局部变量只能在局部作用域生效。当我们在外部访问时就会报错。
作用域链
概念:如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。 就称为作用域链。
如:
// 案例
function f1() { //0级链
function f2() {//1级链
}
}
var num = 456;//0级链
function f3() {//0级链
function f4() { //1级链
function f5() {
}
}
}
区分私有变量和全局变量
- 在全局作用域下声明(预解析的时候)的变量是全局变量
- 在私有作用域中声明的变量和函数形参都是私有变量.
- 在私有作用域中,代码执行的时候遇到了一个变量,首先需要确定是否为私有变量,如果是私有变量,那么和外面的作用域没有任何关系;
函数执行
当函数执行的时候(直接目的:让函数体中的代码执行),首先会形成一个新的私有作用域。
执行代码的就是栈内存,作用域也是栈内存。
- 如果有形参,先给形参赋值
- 进行私有作用域预解析
- 私有作用域的代码从上至下执行
函数形成一个新的私有作用域保护了里面的私有变量不受外界的干扰。(外边变量修改不了私有变量的,私有变量的也修改不了外边变量)
作用域链
如果不是私有变量,则往当前的上级作用域进行查找,如果上级没有则继续查找,则一直找到顶级作用域(window)。
预解析
JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候,分为两步:预解析和代码执行。
预解析过程:
JavaScript解析器会在全局环境下查找 var、function关键字,变量只声明不赋值,函数声明不调用。
预解析只发生在当前作用域下
预解析也叫做变量、函数提升
变量提升
定义变量的时候,变量的声明会被提升到当前作用域的最上面,变量的赋值会提升。
函数提升
JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面
变量名和函数名相同,优先执行 函数
执行过程
变量赋值、函数调用、表达式运算等等。
var num = 10;
function fn(){
console.log(num);
var num = 20;
console.log(num);
}
fn();
在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有的带var,和function的进行提前的声明或定义
var 和 function 关键字:
对于带var 和 function 关键字的在预解析的时候操作
var -> 在预解析的时候只是提前声明了
function -> 在预解析的时候提前的声明了 + 定义 都完成了。
预解析只发生在当前的作用域下进行解析。
一开始只会对widnow环境下的进行预解析,只有函数执行的时候才会对函数中的进行解析