作用域:
变量可以起作用的范围和区域。
不使用 var 声明的变量是全局变量,不推荐使用。
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
变量提升
console.log(a); // undefined
var a = 2;
console.log(a); // a is not defined
变量提升
定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。
函数提升
JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面
f();
function f(){
console.log(12); //12
}
var f = 1;
function f(){
console.log(12); //12
}
// 由于函数提升在前,所以被变量声明替换了;
// 执行阶段,变量被复制为1,不再是一个函数,
f(); // f is not a function
注:不管是普通变量还是函数,尽量不要出现重名;
JS代码的运行
console.log(s); //undefined
var s = 2;
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。
JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析(编译)过程和代码执行过程
预解析过程:
- 语法检查,如果有错误,直接停止后续步骤不再运行。
- 把变量和函数的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值和调用。
- 先提升变量后提升函数,如果函数和变量同名,则被替换;
代码执行过程
- 变量的赋值,函数的调用,循环判断等,根据代码由上往下顺序执行;
var a = 25;
function abc (){
alert(a);//undefined
var a = 10;
}
abc();
// 如果变量和函数同名的话,函数会覆盖变量
console.log(a);
function a() {
console.log('aaaaa');
}
var a = 1;
console.log(a);
// 1、----------------
var num = 10;
fun();
function fun() {
console.log(num); //undefined
var num = 20;
}
// 2、----------------
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); //undefined
console.log(b); // 9
var a = '123';
}
词法作用域
变量的作用域是在定义时决定而不是执行时决定的,也就是说词法作用域取决于编译阶段,通过静态分析就能确定,因此词法作用域也叫做静态作用域。
在 js 中词法作用域规则:
- 函数允许访问函数外的数据.
- 整个代码结构中只有函数可以限定作用域.
- 作用域规则首先使用提升规则分析
- 如果当前作用规则中有名字了, 就不考虑外面的名字
var num = 123;
function foo() {
console.log( num );
}
foo();
if ( false ) {
var num = 123;
}
console.log( num ); // undefiend
函数内部可以访问函数外部的变量,但是函数外部不可以访问函数内部的变量;
函数内部如果有变量,则优先使用内部的变量,如果函数内部没有,才会使用函数外部的变量;
作用域链
只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。
var a = 1;
function fn1(){
function fn2(){
function fn3(){
console.log(a);
}
fn3();
}
fn2();
}
fn1();
//--------------------------------
var a = 1;
function fn1(){
var a = 2;
function fn2(){
var a = 3;
function fn3(){
console.log(a);
}
fn3();
}
fn2();
}
fn1();