Fork me on GitHub

JavaScript之作用域

  JavaScript的作用域一直以来都是前端开发中比较难以理解的知识点,对于JavaScript的作用域,记住下面五句话即可。

一,“JavaScript中无块级作用域”

  在java或者c#中存在块级作用域,即:大括号也是一个作用域

java

public static void main ()
{
    if(1==1){
        String name = "seven";
    }
    System.out.println(name);
}
// 报错

C#

public static void Main()
{
    if(1==1){
        string name = "seven";
    }
    Console.WriteLine(name);
}
// 报错

  在JavaScript语言中无块级作用域

function Main(){
        if(1==1){
                var name = "seven";
        }
        console.log(name);
}
//输出:seven

  补充:标题之所以添加双引号是因为JavaScript6中新引入了let关键字,用于指定变量属于块级作用域。

二,JavaScript采用函数作用域

  在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。

function Main(){
    var innerValue = 'seven';
}
 
Main();
 
console.log(innerValue);
 
// 报错:Uncaught ReferenceError: innerValue is not defined

三:JavaScript的作用域链

  由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,就会出现作用域链。

xo = 'james';
  
function Func(){
    var xo = "seven";
    function inner(){
        var xo = 'durant';
        console.log(xo);
    }
    inner();
}
Func();

  如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

  当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,知道没找到抛出异常。

四,JavaScript的作用域链执行前已创建

示例一:

xo = 'james';
 
function Func(){
    var xo = "durant";
    function inner(){
 
        console.log(xo);
    }
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: durant

  上述代码,在函数被调用之前作用域链已经存在:

  • 全局作用域 -> Func函数作用域 -> inner函数作用域

   当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

示例二:

xo = 'james';

        function Func(){
            var xo = "durant";
            function inner(){

                console.log(xo);
            }
            xo = "curry";
            return inner;
        }

        var ret = Func();
        ret();
//输出结果:curry

 上述代码和示例一的目的一样,也是强调在函数被调用之前作用域链已经存在:

  • 全局作用域 -> Func函数作用域 -> inner函数作用域

  不同的是,在执行var ret = Func()时候,Func作用域中的xo变量的值已经由durant被重置为curry,所以之后在执行ret()的时候,就只能找到curry了。

示例三:

xo = 'james';

        function Func1(){
           console.log(xo);
        }

        function Func2(){
            var xo ='durant';
            return Func1;
        }

        var ret = Func2();
        ret();
//输出结果:james

  上述代码中,在函数被执行之前已经创建了两条作用域链:

  • 全局作用域 -> Func1函数作用域
  • 全局作用域 -> Func2函数作用域

  当执行ret()时候,ret代指的是Func1函数,而Func1函数的作用域链已经存在:全局作用域大于Func1()函数作用域,所以,执行的时候会根据已经存在的作用域链去寻找。

五,声明提前

  在JavaScript中如果不创建变量,直接去使用,则报错:

console.log(a);
// 报错:Uncaught ReferenceError: a is not defined

  JavaScript中如果创建值而不赋值,则该值为undefined,如:

var ret;
console.log(ret);
// 输出:undefined

  在函数中如果这么写:

function Foo(){
    console.log(ret);
    var ret = 'seven';
}
 
Foo();
// 输出:undefined

  上述代码中,不报错而是输出undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于在上述实例中,函数在“预编译”时,已经执行了var ret;所以上述代码中输出的是undefined。

posted @ 2018-11-27 10:50  战争热诚  阅读(320)  评论(0编辑  收藏  举报