zoukankan      html  css  js  c++  java
  • JavaScript的作用域、作用域链和执行期上下文

    转载:https://ambitionc.com/#/Blogs/Blog_9


    JavaScript的作用域、作用域链和执行期上下文

    一、JS的作用域

    1. 基本概念

    (1)作用域是可访问变量的集合,在JavaScript中,作用域为可访问变量,对象,函数的集合。

    (2)JavaScript拥有函数作用域:每个函数创建一个新的作用域。作用域决定了这些变量的可访问性(可见性)。

    (3)在JavaScript中,有两种作用域类型:

    • 局部作用域

    • 全局作用域

    2. JavaScript的局部作用域

    (1)变量在函数内声明,变量为局部作用域,只能在函数内部访问

    // 函数外不可调用
    function myFun() {
        var carName = "Volvo"
        // 函数内可调用carName
    }

    (2)局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁,也就是释放掉。

    3. JavaScript的全局作用域

    (1)全局变量有全局作用域,网页中所有的脚本和函数都可以使用。

    (2)全局变量和全局执行环境直到应用程序退出,如关闭网页或浏览器时才被销毁。

    (3)在HTML中,全局作用域是window,所有全局变量均属于window对象。

    3. 自动全局

      需要注意的是,如果为一个尚未声明的变量赋值,那此变量会自动变成全局变量。

    myFun();
    // 此处可以使用carName变量
    function myFun() {
        carName = "Volvo"
    }

    二、作用域链

    1. 基本概念

    (1)代码在一个环境中执行时,会创建变量对象的作用域链。

    (2)作用域链的用途就是保证对执行环境有权访问所有的变量和函数的有序访问。作用域的最前端,始终都是当前执行的代码所在环境的变量对象。

    (3)作用域链是[[Scope]]中所存储的执行期上下文的集合,这种集合呈链式链接,我们把这种链式连接称为作用域链。

      每一个JavaScript函数都表示为一个对象,更确切的说,是Function对象的一个实例,Function对象和其他对象一样,有一些可以编程访问的属性,和一些不能通过代码访问而仅供JavaScript引擎存取的内部属性,其中一个属性就是[[Scope]]。

      内部属性[[Scope]]包含一个函数被创建的作用域中对象的集合。这个集合被称为函数的作用域链,它决定哪些数据能被函数访问。 ——《高性能JavaScript》

    (4)JS代码在一个环境中执行,会创建变量对象的作用域链,如这个环境是函数,则将活动对象作为变量对象。活动对象最开始只有一个arguments对象,在下一个变量对象来自包含外部环境,再下一个变量对象来自下一个包含环境。这样一直延续到全局执行环境GO。

    三、执行期上下文

    1. 基本概念

    (1)函数执行的时候,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行的环境,函数每次执行时,对应的执行上下文都是独一无二的,多次调用一个函数会导致创建多个执行上下文,函数创建完毕的时候,产生的执行期上下文被销毁。

    (2)执行期上下文是一个存储函数调用的栈结构

    2. JS执行过程

    (1)首先JS执行在单线程,排队执行;

    (2)浏览器执行全局代码时,首先创建执行上下文,压入栈顶;

    (3)函数执行前会创建函数上下文AO,执行完后当前函数执行上下文出栈,等待垃圾回收;

    (4)浏览器的JS引擎总是访问栈顶的执行上下文;

    (5)全局的上下文只有一个,在浏览器关闭的时候出栈。

    四、作用域链的相关优化策略

    1. 标识符解析的性能

      每个执行环境都有自己的作用域链,用于解析标识符。标识符的解析是有代价的,在执行环境的作用域链中,一个标识符所在位置越深,它的读写速度也就越慢。

      函数中读写局部变量总是最快的,而读写全局变量通常是最慢的(优化JavaScript引擎在某些情况下能有所改善),因为全局变量总是存在于执行环境作用域的最末端,因此它也是最远的。

      因此,标识符所在的位置越深,读写速度越慢,因此在没有优化JavaScript引擎的浏览器,如IE、Safari 3.2,建议尽量使用局部变量。如果某个跨作用域的值在函数中被引用一次以上,就把它存储到局部变量里。

    1. 改变作用域链和动态作用域

      尽量避免使用with语句,减少使用try-catch语句。因为使用这些语句会改变作用域链,会增加变量的访问代价。动态作用域无法通过静态解析检测出来,因此需要减少使用。


    转载:https://ambitionc.com/#/Blogs/Blog_9

  • 相关阅读:
    Hibernate HQL查询:
    Struts2里如何取得request,session,application
    Hibernate 报错org.hibernate.PropertyAccessException: IllegalArgumentException(已解决)
    PHP 读取文件的几种方法
    PHP 关于文件操作的简单介绍
    VB 中ListView 某一列的颜色添加不上去的解决方法
    SQL Server 版本号汇总
    C# 单元测试
    Web Api单元测试写法
    git bash 出现vim的时候怎么退出
  • 原文地址:https://www.cnblogs.com/chenhaonan-nickyoung/p/13507185.html
Copyright © 2011-2022 走看看