深入理解jsavascript的作用域

一、 JavaScript声明提前

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

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

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

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

在函数内如果这么写:

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

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

  

  

二、JavaScript以函数为作用域

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

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

 

三、JavaScript函数的作用域栈

 由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域栈(先进后出)。

a = '全局';
  
function Outer(){
    var a = "o";
    function inner(){
        var a = 'i';
        console.log(a);
    }
    inner();
}
Outer();

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

代码从上到下执行的时候,以从外到内的顺序将每个变量入栈。全局变量在栈底部。

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

JavaScript的函数在被执行之前,会将其中的变量全部声明,并在作用域栈中占据相应的坑位。

  

 

四、JavaScript的作用域栈执行前已创建

 JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域栈去寻找即可。参考二的图一,在函数被执行前作用域已经形成了,只是函数变量未被赋值。

示例一:

a= '全局';
 
function Outer(){
    var a= "O";
    function inner(){ 
        console.log(a);
    }
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: O

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

由于函数创建时,作用域已经创建,因此最后的作用域结果入上图。ret=inner。因此执行inner()函数,当然首先查找到本层函数的变量a='O' 。

示例二:

a= '全局';
 
function Outer(){
    var a= "O";
    function inner(){
 
        console.log(a);
    }
    a = 'B';
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: B

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

inner函数中在函数执行钱a变量游“O"被重置为”B",因此最后执行结果为B。

示例三:

a= '全局';

function Bar(){
    console.log(a);
}
 
function Outer(){
    var a= "O";
     
    return Bar;
}
 
var ret = Func();
ret();
// 输出结果: '全局'

 上述代码,在函数被执行之前已经创建了两条作用域链(同级函数会创建个平行作用域,共享他们的父级函数的的变量): 

当执行et();时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

 

其他例子 :

function func() {
            for(i=0;i<3;i++){
                setInterval(function () {
                    console.log(i)
                },1000)
            }
        }
//每秒输出3个3
View Code
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="button" value="按钮1">
    <input type="button" value="按钮2">
    <input type="button" value="按钮3">

    <script>
        inps = document.getElementsByTagName("input")
        for(i=0;i<3;i++){
            cur_inp = inps[i];
            cur_inp.onclick = function () {
                alert(3)
            }
        }
        //所有的按钮点击都是输出3
    </script>
</body>
</html>
View Code

  

原文地址:https://www.cnblogs.com/tkqasn/p/5745913.html