说说 JavaScript 执行环境以及作用域

来源:互联网 发布:玩淘宝要费多少流量 编辑:程序博客网 时间:2024/06/07 01:51
  • 全局执行环境是最外围的执行环境。
  • 在 web 浏览器中,全局执行环境是 window 对象。
  • 全局执行环境直到应用程序退出才会被销毁。
  • 每个函数都有自己的执行环境。在执行一个函数时,函数的环境会被推入环境栈中,函数执行后,函数的环境会从当前栈中弹出,把控制权返回给之前的执行环境。
  • 当代码在一个环境中执行时,会创建变量对象的作用域链。它的用途是保证执行环境有权访问所有变量和函数。
  • 全局执行环境的变量对象是作用域链的最后一个对象。
  • 标识符的解析是沿着作用域链一级一级搜索,搜索过程从作用域链的前端开始,然后逐级向后回溯,直到找到标识符为止(找不到会报错):
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>函数内部可以在作用域链中找到全局环境的变量</title></head><body><script type="text/javascript">    var color = "blue";    function changeColor(){        if (color === "blue"){            color = "green";        } else {            color = "blue";        }    }    changeColor();    console.log("Color is now " + color);//green</script></body></html>
  • 函数内部可以在作用域链中找到祖先环境下的变量:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>函数内部可以在作用域链中找到祖先环境下的变量</title></head><body><script type="text/javascript">    var color = "blue";    function changeColor(){        var anotherColor = "green";        function swapColors(){            var tempColor = anotherColor;            anotherColor = color;            color =tempColor;            // 可以访问 color、anotherColor 和 tempColor        }        swapColors();        // 可以访问 color、anotherColor    }    changeColor();    console.log("Color is now " + color);//green    // 可以访问 color</script></body></html>
  • 作用域链示意图:

  • 函数的内部环境可以通过作用域链访问所有的外部环境,这些环境之间的联系是线性、有次序的。
  • 每个环境都可以向上搜索作用域链。
  • 函数参数也被当做变量来对待,所以其访问规则与执行环境中的其他变量相同。

1 延长作用域链

当执行流进入下列语句时,作用域链会延长:
* try-catch 语句中的 catch 块
* with 语句

这些语句会在作用域的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。

  • 对于 catch 语句,会创建一个新的变量对象,其中包含被抛出的错误对象的声明。
  • 对于 with 语句:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>延长作用域链</title></head><body><script type="text/javascript">    function buildUrl(){        var qs = "?debug=true";        with (location){            var url = href + qs;        }        return url;    }    console.log(buildUrl());</script></body></html>
  • 例子中的 with 语句接收的是 location 对象,所以其变量对象就包含了 location 对象的所有属性和方法。

在 IE8及之前的版本中, catch 语句捕获的错误对象会被添加到执行环境的变量对象,而不是 catch 语句的变量对象,IE9 修复了这个问题

2 没有块级作用域

  • 其他类 C 的语言中,由花括号封闭的代码块都有块级作用域,但 JavaScript 没有!
if (true){    var color = "blue";}console.log(color); //"blue"
  • if 语句中声明的变量会将变量添加到当前的执行环境中!!在使用 for 语句时尤其要牢记这一点:
for (var i=0; i < 10; i++){    doSomething(i);}alert(i);//10

2.1 声明变量

  • 使用 var 声明的变量会被自动添加到最接近的环境中。在函数内部,到最接近的环境是函数局部环境;在 with 语句中,是函数环境。
  • 函数的局部变量,在函数外部无法访问:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>函数的局部变量,在函数外部无法访问</title></head><body><script type="text/javascript">    function add(num1, num2){        var sum = num1 + num2;        return sum;    }    console.log(add(10,20));//30    console.log(sum);//错误</script></body></html>
  • 如果初始化变量没有使用 var 声明,变量会被自动添加到全局环境中:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>函数内定义的变量(省略了 var),在函数外部可以访问</title></head><body><script type="text/javascript">    function add(num1, num2){        sum = num1 + num2;        return sum;    }    console.log(add(10,20));//30    console.log(sum);//30(全局变量)</script></body></html>
  • 建议在初始化变量之前,一定要先声明,这样可以避免这些问题。
  • 在严格模式下,初始化未经声明的变量会报错。

2.2 查询标识符

  • 搜索会从作用域链的前端开始,向上逐级查询标识符。如果在全局环境下也没有找到,即意味着这个变量还未声明:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>沿作用域链向上搜索标识符定义</title></head><body><script type="text/javascript">    var color = "blue";    function getColor(){        return color;    }    console.log(getColor());//blue</script></body></html>
  • 如果局部环境中存在同名的标识符,就不会使用父环境中的标识符:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title>沿作用域链向上搜索标识符定义,找到立即停止搜索</title></head><body><script type="text/javascript">    var color = "blue";    function getColor(){        var color = "green";        return color;    }    console.log(getColor());//green</script></body></html>
0 0
原创粉丝点击