js 作用域链

  1. js 作用域链
  2. 局部作用域
  3. 全局作用域
  4. 多层函数嵌套

js 作用域链

局部变量:在函数中通过var声明的变量。

全局变量:在函数外通过var声明的变量。

没有声明就使用的变量,默认为全局变量,不论这个变量在哪被使用。

局部作用域

在函数内部定义的变量,为局部变量,局部变量只能在该局部作用域中访问

function fn1() {
    var username = 'jerry';
    console.log(username);
}
fn1()   // jerry

此时在全局访问username,则会报错

 console.log(username);  // 报错,username未定义

全局作用域

函数内部和外部都可以访问该变量

var age = 12;
function fn2() {
    console.log(age);
}
fn2()     // 12

console.log(age);  // 12

如果在函数内部没有使用var定义变量,那么 gender = ‘male’;就是个赋值语句,会找到最近的定义的变量进行赋值(注意变量提升),如果都没找到,则为全局变量

function fn3() {
    gender = 'male';
    console.log(gender);
}
fn3();

如果上面的函数没有调用,那么在外面使用gender会报错,因为在 fn3() 被第一次调用之前, gender变量是不存在的。fn3() 被调用过之后,gender成为全局变量

多层函数嵌套

如果内层函数没有使用var定义变量,则可以看做是赋值语句,会向上层依次找到该变量的定义语句,并赋值给它,如果向上找都没有没找到,则为全局变量

这里在fn5函数这个作用域中没有找到num,则向上查找,找到fn4作用域中的num,赋值为100,则下面的fn4里在fn5调用后的num100

var num = 1;
function fn4() {
    var num = 10
    console.log('fn4里在fn5调用前的num ' + num);
    function fn5() {
        num = 100
        console.log('fn5里的num ' + num);
    }
    fn5()
    console.log('fn4里在fn5调用后的num ' + num);
}
fn4()
console.log('全局的num ' + num);

输出结果:

fn4里在fn5调用前的num 10
fn5里的num 100
fn4里在fn5调用后的num 100
全局的num 1

这里在fn5函数内部的num = 100后面加了一个var num = 200,此时由于存在变量提升,num定义提升到函数顶部,并初始化为undefined,然后赋值num = 100(这里赋值的是fn5函数内部提升的num),再赋值num = 200,因此fn5里的num输出200,而fn4里在fn5调用后的num输出10

var num = 1;
function fn4() {
    var num = 10
    console.log('fn4里在fn5调用前的num ' + num);
    function fn5() {
        num = 100
        var num = 200
        console.log('fn5里的num ' + num);
    }
    fn5()
    console.log('fn4里在fn5调用后的num ' + num);
}
fn4()
console.log('全局的num ' + num);

输出结果:

fn4里在fn5调用前的num 10
fn5里的num 200
fn4里在fn5调用后的num 10
全局的num 1

这里在fn5函数内部的num = 100后面加了一个let num = 200,此时由于存在变量提升,num定义提升到函数顶部,但并不会初始化为undefined(这是由于let的变量提升和var的变量提升有差异导致的),此时num提升之后,执行num = 100,但是由于仅仅提升了变声声明,这个时候并没有初始化为undefined,因此会报错Uncaught ReferenceError: Cannot access 'num' before initialization

var num = 1;
function fn4() {
    var num = 10
    console.log('fn4里在fn5调用前的num ' + num);
    function fn5() {
        num = 100
        let num = 200
        console.log('fn5里的num ' + num);
    }
    fn5()
    console.log('fn4里在fn5调用后的num ' + num);
}
fn4()
console.log('全局的num ' + num);

输出结果:

fn4里在fn5调用前的num 10
报错: `Uncaught ReferenceError: Cannot access 'num' before initialization`

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com