JavaScript - 作用域

1、作用域简介

  作用域是可访问变量的集合

  作用:控制着变量与参数的可见性和生命周期

  优点:(1)减少了名称冲突;(2)提供了自动内存管理; (3)可以访问它们的外部函数的参数和变量,除了this和arguments

  分类:(1)全局作用域(Global Scope); (2)块级作用域(Block level scope)

2、JavaScript作用域

   注意:JavaScript无块级作用域!!!

  分类:(1)全局作用域;(2)局部作用域(函数作用域)

  在 JavaScript 中, 对象和函数同样也是变量,作用域为可访问变量,对象,函数的集合。

  1)JavaScript全局作用域

    定义:全局变量用拥有全局作用域。

    使用范围:(1)最外层函数和在最外层函数外面定义的变量

         (2)所有未定义直接赋值的变量

         (3)所有Windows对象的属性

  2)JavaScript局部作用域(函数作用域)

    定义:在函数内部访问的变量为局部变量,局部变量拥有局部作用域。

    使用范围:(1)特定的代码片段,或者函数中

    特点:(1)不同函数可以使用相同的变量名;

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

  3)作用域链和标识符解析

    (1)在JavaScript里,万物皆对象,而对象拥有可以编程访问的属性,和一系列不能通过代码访问而仅供JavaScript引擎存取的内部属性,[[Scope]]是其中之一。

  [[Scope]]包含了一个函数被创建的作用域中对象的集合,这个集合被称作函数的作用域链。

    (2)作用:决定哪些数据能被函数访问

    (3)函数作用域中的每个对象被称为一个可变对象,每个可变对象都以“键值对”的形式存在。

    例(全局函数):  

function add(num1, num2){

    var sum = num1 + num2;

    return sum

}    

     JavaScript - 作用域_第1张图片

    (4)执行环境(执行上下文): 执行函数是创建的一个内部对象。

调用一次函数就会创建一个执行环境,多次调用同一个函数就会创建多个执行环境。当函数执行完毕,执行环境就会被销毁。

每个执行环境都有自己的作用域链,用于解析标识符。

JavaScript - 作用域_第2张图片

活动对象,作为函数运行时的变量对象,包含所有局部变量,命名参数,参数集合以及this。此对象被推入作用域链的最前端。随执行环境的创建而创建,销毁而销毁。

全局对象,随函数创建而创建,销毁而销毁。

(5)在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程,以决定从哪里获取或存储数据。每个标识符都要经历这个过程。(所有会影响性能)

  变量遮蔽性,名字相同的连个变量存在于作用域链的不同部分,那么标识符就是遍历作用域链时最先找到的哪个。

(6)标识符解析的性能

  标识符解析是需要代价的。

全局变量总是存在于执行环境作用域链的最末端。

在执行环境的作用域链中和所有游览器而言,一个标识符所在的位置越深,它的读写速度越慢。

 JavaScript - 作用域_第3张图片

  4)改变作用域链

    可临时改变作用域链的语句:(1)with语句;(2)try-catch中的catch子句

(1) with语句

  作用:给对象的所有属性创建一个变量。

  优点:减少代码量

  缺点:易产生性能问题(一个新的变量对象被创建,它包含了参数指定的对象的所有属性。这个对象被推入作用域链的首位,而函数的局部变量处于作用域链的第二位,因此访问代价更高了)

 (2) try-catch中的catch子句

  理由:try代码块中发生错误,执行过程自动跳转到catch子句,然后把异常对象推入一个变量对象饼置于作用域链的首位。在catch代码块内部,函数所有局部变量将会放在第二作用域链对象中

  解决办法:尽量简化代码;将错误委托给一个函数来处理

 5)动态作用域

(1) 只存在于代码执行过程中,因此无法通过静态分析(查看代码结构)检测出来

(2) 设计动态作用域时,优化的JavaScript引擎就失效了。脚本引擎就必须切回较慢的哈希表的标识符识别方式,这更像是传统的作用域链查找。因此,只有在确切必要时才推荐使用动态作用域

(3) 种类:with语句;try-catch语句的catch子句;包含eval()的函数

  eval() => 把一个字符串当作js表达式一样去执行

(4) 例:

function execute(code){
    eval(code);
    function subroutine(){
        return window;
    }
    var w = subroutine();
    console.log(w)
}

变量w的值会随code的变化而变化。一般情况下,w=全局的window对象,当code=var window = {}时;  w的值就为 {}。如下图所示:

JavaScript - 作用域_第4张图片

因为eval() 创建了一个局部变量window,此时w的值为局部变量window,而不是全局window对象。

你可能感兴趣的:(JavaScript - 作用域)