第一章 作用域

1、理解作用域

几个名词的介绍

引擎:从头到尾负责整个JavaScript程序的编译及执行过程

编译器:负责语法分析及代码生成器等脏活累活

作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。

对var a = 2;进行分解,了解引擎等是如何工作。

编译器首先将这段程序分解成词法单元,然后将词法单元解析成一个树结构。但是当编译器开始进行代码生成时,它对这段程序的处理方式会和预期的有所不同。

编译器会进行如下处理

1)遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一作用域的集合中。如果是,编译器会忽略该声明,继续2进行编译;否则它会要求作用域在当前作用域的集合中声明一个新变量,并命名为a。

2)接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作a的变量。如果是,引擎就会使用这个变量;如果否,引擎就会继续查找该变量。如果引擎最终找到了a变量,就会将2赋值给它。否则引擎就会抛出异常。

总结:变量的赋值操作会执行两个动作,首先编译器会编译当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对他赋值。

2、编译器的LHS和RHS

变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询

考虑以下代码:

console.log(a);

其中对a的引用是一个RHS引用(因为这里是将a的值传递给console.log(..))。

相比之下,例如:

a = 2;

这里对a的引用则是LHS引用,将2的值赋给a。

总结:LHS和RHS的含义是 "赋值操作的左侧或右侧" 并不一定意味着就是 "=赋值操作符的左侧或右侧" 。赋值操作还有其他几种形式,因此在概念上最好将其理解为 "赋值操作的目标是谁(LHS)" 以及 "谁是赋值操作的源头(RHS)" 。

考虑下面程序,其中既有LHS也有RHS引用:

function foo () {
console.log(a); //2
} foo(2);

最后一行 foo(..) 函数的调用需要对foo进行RHS引用,意味着 "去找到foo的值,并把它给我" 。并且(..)意味着foo的值需要被执行,因此它最好真的是一个函数类型的值!

代码中隐式的a = 2操作可能很容易被忽略,这里进行了一次LHS查询。

小测试:

function foo(a) {
var b = a;
return a + b;
}
var c = foo(2);

1)、找到所有的LHS查询

c = ..;、a = 2(隐式变量分配)、b = ..

2)、找到所有的RHS查询

foo(2..、=a;、a..、..b

3、作用域嵌套

当一个块或函数嵌套在另外一个块或函数时,就会发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(也就是全局作用域)为止。

4、异常

在变量还没有声明(在任何作用域中都无法找到该变量)的情况下,LHS和RHS两种查询的行为是不一样的。

考虑如下代码:

function foo(a) {
console.log(a + b);
b = a;
}
foo(2);

第一次对b进行RHS查询时无法找到该变量的。也就是说,这是一个 "未声明" 的变量,因为在任何相关的作用域中都无法找到它。

如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出ReferenceError异常。值得注意的是,ReferenceError是非常重要的异常类型。

相比较之下,当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非 "严格模式" 下。

接下来,如果RHS查询找到了一个变量,但是你尝试对这个变量进行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或者引用null或undefined类型的值中的属性,那么引擎会抛出另外一个类型异常,叫作TypeError。

ReferenceError同作用域判别失败相关,而TypeError则代表作用域判别成功了,但是对结果操作是非法或不合理的。

【读书笔记】你不知道的JavaScript(上卷)--作用域是什么的更多相关文章

  1. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  2. 你不知道的JavaScript上卷笔记

    你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章   初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...

  3. 你不知道的javaScript上卷(第一章 作用域是什么)

    在写这篇博客时这本书我已经是看过一遍了,为了加深印象和深入学习于是打算做这系列的前端经典书籍导读博文,大家如果觉得这本书讲的好可以自己买来看看,我是比较喜欢看纸质版书的,因为这样才有读书的那种感觉. ...

  4. 《你不知道的 JavaScript 上卷》 学习笔记

    第一部分: 作用域和闭包 一.作用域 1. 作用域:存储变量并且查找变量的规则 2. 源代码在执行之前(编译)会经历三个步骤: 分词/此法分析:将代码字符串分解成有意义的代码块(词法单元) 解析/语法 ...

  5. 读《你不知道的JavaScript(上卷)》后感-作用域闭包(二)

    github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...

  6. 读《你不知道的JavaScript(上卷)》后感-浅谈JavaScript作用域(一)

    原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们,也入手看看这 ...

  7. 【你不知道的javaScript 上卷 笔记3】javaScript中的声明提升表现

    console.log( a ); var a = 2; 执行输出undefined a = 2; var a; console.log( a ); 执行输出2 说明:javaScript 运行时在编 ...

  8. 你不知道的JavaScript之作用域

    什么是作用域 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代 码块被称为词法单元(token) 解析/语法分析 这个过程是将词法单元流(数组)转 ...

  9. JavaScript词法作用域—你不知道的JavaScript上卷读书笔记(一)

    前段时间在每天往返的地铁上抽空将 <你不知道的JavaScript(上卷)>读了一遍,这本书很多部分写的很是精妙,对于接触前端时间不太久的人来说,就好像是叩开了JavaScript的另一扇 ...

  10. JS闭包—你不知道的JavaScript上卷读书笔记(二)

    关于闭包,初学者会被绕的晕头转向,在学习的路上也付出了很多精力来理解. 让我们一起来揭开闭包神秘的面纱. 闭包晦涩的定义 看过很多关于闭包的定义,很多讲的云里雾里,晦涩难懂.让不少人以为闭包是多么玄乎 ...

随机推荐

  1. pat1087. All Roads Lead to Rome (30)

    1087. All Roads Lead to Rome (30) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...

  2. pat1086. Tree Traversals Again (25)

    1086. Tree Traversals Again (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...

  3. c++ 面试整理

    1. 继承方式 public    父类的访问级别不变 protected    父类的public成员在派生类编程protected,其余的不变 private        父类的所有成员变成pr ...

  4. Linux Bird

    o / : 2GB o /boot: 200MB o /usr : 4GB o /var : 2GB o /tmp : 1GB o swap : 1GB o /home: 5GB,并且使用 LVM 模 ...

  5. csdn下载

    按次收费: http://www.itziy.com/

  6. Vue.js - Day3

    定义Vue组件 什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可: 组件化和模块化的不同: ...

  7. 在CentOS上配置redis服务

    #!/bin/sh # # redis Startup script for Redis Server # # chkconfig: - 80 12 # description: Redis is a ...

  8. 认识less和webstrom的less配置

    认识less和webstrom的less配置 今天完成的事情: 首先第一件事情是,整理一下常用的颜色摄取 #F1F1F1 google的设置页面的body的背景颜色 #FFF 为google的内容块的 ...

  9. python模块详解 logging

    打印日志的五个级别: import logging logging.debug('test debug') logging.info('test info') logging.warning('tes ...

  10. 时域反射计(TDR)原理与应用

    [施工编辑中...] 1. 什么是TDR? TDR = Time Domain Reflectometry 时域反射计TDR用来测量信号在通过某类传输环境传导时引起的反射,如电路板轨迹.电缆.连接器等 ...