关于变量作用域的知识,相信学习JavaScript的朋友们一定早已经接触过,这里简单列举:

  • JavaScript中变量是以对象属性的形式存在的:全局变量是全局对象的属性;局部变量是声明上下文对象的属性。(声明上下文对象是一个对用户不可见的内部实现,无法被引用,每当函数调用便创建这个对象以存放局部变量)
  • JavaScript虽然是解释型语言,但也存在预处理过程,其中便包含了声明提前。JavaScript解释器运行前,会先将整个程序中的变量声明(包括函数)提前到作用域顶部执行。所以在程序中变量的使用语句可以出现在声明语句之前。
  • JavaScript中没有块级作用域(像C语言那样用方括号{}划分作用域),而是使用函数作用域;
  • 不在任何函数体内声明的变量为全局变量,拥有全局作用域,可以在程序的任何位置被访问;而在函数内声明的变量(包括函数的参数)为局部变量,拥有局部作用域,只在函数内部有定义;
  • 若局部变量与全局变量重名,局部变量优先级高,可以遮盖全局变量;
  • 局部作用域可以相互嵌套(因为函数可以嵌套)

    而作用域链的概念,接触过的人就没那么多了。其实作用域链很好理解,上方第一条已经明确了,JavaScript中变量是以对象属性的形式存在的,而作用域链其实就是这些对象组成的一个链表。全局变量是全局对象的属性,局部变量是声明上下文对象的属性。这些对象按从内向外的顺序链接,链尾当然就是全局对象。当函数运行中需要查找某一个变量的时候,就会沿着作用域链依次查询每个对象是否拥有与该变量同名的属性,如果存在则直接使用;若整条链上都不存在这个属性,便抛出ReferenceError。
在函数定义的时候,便创建了作用域链,链上的对象顺序便确定下来,当函数被调用,创建相应的对象添加到作用域链中,作用域链会随着函数的定义调用而更新。在嵌套函数中更是如此,每次调用外部函数时,内部函数又会重新定义,随之带来的就是作用域链的相应变化。关于作用域链的数量,可以用树来比喻,全局对象是根节点,函数的嵌套代表着树节点的层级关系,那么一个程序中作用域链的数量等于对应树中叶子节点的数量。
var a = 1;// 最外层的作用域链上只有全局对象

function func1(){
var a = 2; // 这一层的作用域链: func1的声明上下文对象 ——> 全局对象
function func2(){
var a = 3; // 这一层的作用域链: func2的声明上下文对象 ——> func1的声明上下文对象 ——> 全局对象
console.log("in func2's scope a= " + a + " ");
}
func2();
console.log(console.log("in func1's scope a= " + a + " ");)
}
func1();
console.log(console.log("a= " + a + " "););


    运行结果可以很清楚的反映出作用域链的查询顺序。

     关于作用域链还不得不提with语句,它可以进行临时性作用域链扩展。它的语法是这样的:with(object){ statement }。 它将object添加到作用域链的顶部,然后执行语句,执行完毕后将作用域链恢复到原始状态。在对象嵌套层次很深的时候,可以使用with语句简化代码。下面的两段代码是等价的:
var object = {
object1: {
name : {
firstName: "hello",
lastName: "world",
nickName: "Jeff"
}
}
};
object.object1.name.firstName = "aaa";
object.object1.name.lastName = "bbb";
object.object1.name.nickName = "ccc";
var object = {
object1: {
name : {
firstName: "hello",
lastName: "world",
nickName: "Jeff"
}
}
}; with(object.object1.name){
firstName = "aaa";
lastName = "bbb";
nickName = "ccc";
}

with语句在严格模式中是被禁止使用的,在非严格模式也不推荐使用。使用with语句的代码难以优化,并且运行速度更慢。所以上面这种情况我们可以使用下面的方法等价使用,减少代码:

var object = {
object1: {
name : {
firstName: "hello",
lastName: "world",
nickName: "Jeff"
}
}
};
var temp = object.object1.name;
temp.firstName = "aaa";
temp.lastName = "bbb";
temp.nickName = "ccc";


简述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篇-----函数作用域,函数作用域链和声明提前

    在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...

  5. javascript笔记:javascript的关键所在---作用域链

    javascript里的作用域是理解javascript语言的关键所在,正确使用作用域原理才能写出高效的javascript代码,很多javascript技巧也是围绕作用域进行的,今天我要总结一下关于 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 【刷题】AtCoder Regular Contest 001

    A.センター採点 题意:给一个只包含1.2.3.4的字符串,求出现次数最多和最少的字符 做法:还能怎么做... #include<bits/stdc++.h> #define ui uns ...

  2. 洛谷P3628 [APIO2010]特别行动队(动态规划,斜率优化,单调队列)

    洛谷题目传送门 安利蒟蒻斜率优化总结 由于人是每次都是连续一段一段地选,所以考虑直接对\(x\)记前缀和,设现在的\(x_i=\)原来的\(\sum\limits_{j=1}^ix_i\). 设\(f ...

  3. [luogu1447][bzoj2005][NOI2010]能量采集

    题目大意 求出\(\sum_{i=1}^{n} \sum_{i=1}^{m} gcd(i,j)\times 2 -1\). 题解 解法还是非常的巧妙的,我们考虑容斥原理.我们定义\(f[i]\)表示\ ...

  4. centos7 安装mysql的正确姿势

    1. 添加MySQL Yum源 MySQL官网>DOWNLOADS>MySQL Yum Repository找到合适版本的yum源 $wget https://dev.mysql.com/ ...

  5. Red Hat 6.3安装gcc gc++

    首先安装gcc需要相应的rpm依赖包,在安装系统的镜像文件中就有这些rpm包 首先在光驱中选择系统的安装包载入 如果桌面显示有如下的光驱 说明是已经载入了镜像,这时候,需要挂载一下镜像到mnt目录 先 ...

  6. (转)Visual Studio控制台程序输出窗口一闪而过的解决方法

    背景:熟悉visiual studio工具的使用 刚接触 Visual Studio的时候大多数人会写个Hello World的程序试一下,有的人会发现执行结束后输出窗口会一闪而过,并没有出现Pres ...

  7. MSSQL获取当前插入的ID号及在高并发的时候处理方式

    SQL Server 2000中,insert数据的时候返回自动编号的id,有三种方法实现SCOPE_IDENTITY.IDENT_CURRENT 和 @@IDENTITY,它们都返回插入到 IDEN ...

  8. Vetur:VSCode下强大的Vue开发工具

    Vue自从发布以来就一直受到前端开发人员的热爱,而除了一些本身优秀的特征之外,还有就是丰富的插件和工具的支持和更新.虽然现在的编辑器需要安装相应的plugins才能进行Vue组件化开发,但是越来越多优 ...

  9. QtCreator添加第三方头文件和类库

    在Qt Creator的项目中添加头文件和库 在Qt Creator中的工程中,工程通过.pro文件管理. 额外需要连接的连接库 unix:LIBS += -L your_lib_path -lyou ...

  10. 十三、java_GUI

    目录: 一.AWT 二.组件和容器 三.布局管理器 四.事件处理 五.java图形 六.window事件 一.AWT AWT(Abstract Window Toolkit)包括了很多类和接口,用于J ...