今天是2016的第一天,我们得扬帆起航踏上新的征程了。此篇阐述JavaScript中很重要的几个概念:作用域与作用域链及相关知识点。

我们先从变量与作用域的行为关系开始讨论。

变量作用域

JavaScript中,变量有全局变量及局部变量之分,而能定义变量作用域的语块只有函数。与局部变量有关的一种有趣特性,在此处不得不谈--变量提升。

变量提升

变量提升为何物?

JavaScript的变量声明会被提升到它们所在函数的顶部,而初始化仍旧在原来的地方。JavaScript引擎并没有重写代码:每次调用函数时,声明都会重新提升。


    var name = 'Jog'; //全局变量
    function prison() {
        console.log(a); //输出undefined
        var a = 1;//局部变量
        console.log(a); //输出1
        console.log(name); //输出Jog
    }
    prison();

    var name = 'Jog';
    function prison() {
        console.log(name); //输出undefined
        var name = 'Hans';
    }
    prison();

此处name的声明被提升到函数的顶部,变量查找时先从局部作用域开始,未找到则由内而外最后到全局作用域。

接下来我们详细分析一下JavaScript的提升方式。

变量提升与执行环境对象

学习任何一门语言,都像学习魔术一样,初时引人迷惑,惊叹;然而当秘密被揭开时几乎令人失望,JavaScript不外如是。

  • 1. 提升

执行某代码块时,JavaScript引擎先解释,再运行。解释过程主要几个过程:

- (1) 声明该作用域内var变量
- (2) 声明并初始化函数参数
- (3) 声明并初始化声明式函数

详细可查看本系列笔记JavaScript之解释与执行机制

  • 2. 执行环境与执行环境对象

执行环境(execution context)是一种概念,每当函数被调用都会产生一个新的执行环境。

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

- 1. 每个函数都有自己的执行环境。  当执行流进入一个函数时,执行环境就被推入一个环境栈中;函数执行之后,栈将其执行环境弹出,控制权返回到之前的执行环境。
- 2. 如果变量在当前执行环境内可访问,则该变量在当前作用域内。
- 3. JavaScript访问变量,其实就是访问该执行环境对象(变量对象)中的属性。
- 4. 全局执行环境是最外围的一个执行环境。

执行环境对象--每个执行环境都有一个与之对应的变量对象,执行环境中定义的所有变量和函数都保存在这个对象中。


    function fn(arg) {
        var name = 'Far';
        inner();
        function inner() {
            console.log('inner');
        }
    }
    fn('test');

在调用fn时,其过程如下

- 1. 创建一个空执行环境对象;
- 2. 声明参数并赋值;{arg: 1}
- 3. 声明局部变量;{arg:1, name: undefined}
- 4. 预定义声明式函数;{arg:1, name: undefined, inner: function(){console.log('inner');}}
- 5. 代码执行时,局部变量被赋值;{...name: 'Far'...}
- 6. 执行环境对象上变量和函数属性保持不变,调用inner函数时,其内部会创建一个新的执行环境对象,依此可递归形成一条作用域链。

作用域与作用域链

当一个变量在某执行回家内可以被访问,我们称该变量在当前作用域内。

代码某一执行环境中执行时,会创建该执行环境对应的变量对象的一个作用域链。

JavaScript引擎在执行环境对象中查找作用域内的变量或函数,其查找顺序由内而外向上直到全局执行环境对象,这个顺序就形成作用域链。

作用域链的前端,始终是当前执行环境对应的变量对象。若此执行环境是函数,则将其活动对象作为变量对象。作用域链中的下一个变量对象来自于当前变量对象的包含(外部)执行环境,如此一直到全局执行环境;全局执行环境的变量对象始终是作用域链中的最后一个变量对象。


    var age = 22;
    var country = 'China';
    var name = 'Java';
    var job = 'Web';
    function outer() {
        console.log(age);  //输出22
        console.log(country); //输出undefined
        var country = 'Union';
        var name = 'Python';
        inner();
        function inner() {
            console.log(name); //输出Python
            console.log(job); //输出Web
        }
    }
    outer();

代码输出结果如上:

- 1. outer函数执行时,首先在outer执行环境对象中查找age和country变量结果country存在但并未初始化赋值,输出undefined;而age未找到于是沿着作用域链向上到全局执行环境,在其变量对象中存在age属性,于是输出其值22.
- 2. inner函数执行时创建自己的执行环境对象,其并没有定义name和job等变量,于是沿着作用域链向上到达outer函数的执行环境,在其变量对象中存在name于是输出其值Python;而未找到job于是继续向上直到全局执行环境,找到并输出其值,结束;若依然未找到,则会报错,停止运行。

注:函数参数亦被当作变量对待,故其访问规则与普通变量相同。

延长作用域链

某些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行结束后移除。常见如:

  • try-catch语句; catch语句会创建一个新变量对象,包含被抛出的错误对象的声明。
  • with语句; with语句会创建一个包含语句接收对象的所有属性和方法的变量对象。

    function getAttr(data) {
        var obj = data;
        with(obj) {
            var o = location;
        }
        console.log(o);
    }
    getAttr(window);

上面with语句接收window对象,其创建的变量对象就包含了window对象所有属性和方法,于是可以在其执行环节直接访问location变量,也就是正常的window.location。

强烈建议不要使用with语句。

本篇笔记阐述JavaScript执行环境与执行环境对象,变量对象,作用域与作用域链,耗时四小时,还有诸多不足之处待日后补充改进。

JavaScript之作用域与作用域链的更多相关文章

  1. 深入理解 JavaScript 变量的作用域和作用域链

    一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...

  2. 一步步学习javascript基础篇(2):作用域和作用域链

    作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = & ...

  3. 关于Javascript作用域及作用域链的总结

    本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...

  4. 浅谈JavaScript中的变量、参数、作用域和作用域链

    基本类型和引用类型 在JavaScript中有两种数据类型值.基本类型值和引用类型值.基本类型值指的是简单的数据段,而引用类型值指的是可能由多个值构成的对象.在JavaScript中有5种基本数据类型 ...

  5. JavaScript的作用域与作用域链

    作用域 作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.可以说,变量和函数在什么时候可以用,什么时候被摧毁,这都与作用域有关. JavaScript中,变量的作用域有全局 ...

  6. javascript作用域和作用域链摘录

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  7. JavaScript高级之词法作用域和作用域链

    主要内容: 分析JavaScript的词法作用域的含义 解析变量的作用域链 变量名提升时什么 一.关于块级作用域         说到JavaScript的变量作用域,与咱们平时使用的类C语言不同. ...

  8. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  9. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(转载 学习中。。。)

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  10. Javascript的作用域、作用域链以及闭包

    一.javascript中的作用域 ①全局变量-函数体外部进行声明 ②局部变量-函数体内部进行声明 1)函数级作用域 javascript语言中局部变量不同于C#.Java等高级语言,在这些高级语言内 ...

随机推荐

  1. PHP上传原理及应用

    概要 1.FORM表现enctype属性 2.$_FILES系统函数 3.move_uploaded_file函数 4.is_uploaded_file函数 1.FORM标签的enctype属性 只有 ...

  2. oc常用正则表达式

    常用的第三方正则库: http://regexkit.sourceforge.net/RegexKitLite/index.html 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹 ...

  3. 【转】 UIView如何管理它的子视图

    原文:http://my.oschina.net/u/1984662/blog/293690 目录[-] Core Animation基础 改变视图的层 动画支持 视图坐标系统 边框.边界.和中心的关 ...

  4. MVC5+EF6 入门完整教程一

    第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定". 直接讲这些 "约定" 会让人困惑,而且东西太多容易忘记 ...

  5. 数据挖掘相关的10个问题[ZZ]

    NO.1 Data Mining 和统计分析有什么不同? 硬要去区分Data Mining和Statistics的差异其实是没有太大意义的.一般将之定义为Data Mining技术的CART.CHAI ...

  6. 【转】jquery两稳定版本比较~~

    博客分类: Web前端 jquery  jquery历经了多个版本的更新,版本上的比较貌似没什么必要性,一般来说新的版本会比旧的版本各方面都略有提升,但由于新版中增加了各种新的功能,难免会引起bug的 ...

  7. LA 6474 Drop Zone (最小割)

    题目链接 要添最少的挡板使所有的'D'不存在到达网格外的路径. 以每个格子向四个方向中可以到达的格子连容量为1的边, 从源点向所有'D' 连容量为4的边,网格外的点向汇点连一条容量为4的边. 答案就是 ...

  8. jQuery慢慢啃筛选(四)

    1.eq(index|-index) 获取第N个元素 其中负数:一个整数,指示元素的位置,从集合中的最后一个元素开始倒数.(1算起) $("p").eq(1)//获取匹配的第二个元 ...

  9. 《uname命令》-linux命令五分钟系列之五

    本原创文章属于<Linux大棚>博客. 博客地址为http://roclinux.cn. 文章作者为roc 希望您能通过捐款的方式支持Linux大棚博客的运行和发展.请见“关于捐款” == ...

  10. html5 DeviceOrientation来实现手机网站上的摇一摇功能

    原文地址:http://www.cootm.com/?p=706 从网上转载看到的,感觉不错,就转过来了,特此感谢 cnblogs 的 幸福2胖纸的码农生活,直接转载了,不要介意!呵呵 以下是转载内容 ...