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

时间:2023-02-23 14:56:51

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

本期我给大家讲述的是     前端经典js书籍   <<你不知道的javaScript(上卷)>> 第一章内容的知识点总结和讲解。

1.1 编译原理

尽管通常将js归类为“动态”或“解释执行”语言,但事实上它是一门编译语言。但与传统的编译语言不同,他不是提前编译的,编译结果也不能在分布式系统中进行移植。在传统编译语言的流程中,程序中的一段源代码在执行之前会经历三个步骤,统称为“编译”。

1>分词/词法分析

这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元。例如,考虑程序 var a=2;这段程序通常会被分解成为下面这些词法单元 :   var 、a、=、2、;。空格是否会被当做词法单元,取决于空格是否在这门语言中具有意义。

2>解析/语法分析

这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树称为“抽象语法树”(AST)。

3>代码生成

将AST转换为可执行代码的过程被称为代码生成。这个过程与语言、目标平台等息息相关。抛开具体细节,简单的来说就是有某种方法可以将   var  a=2 ;的AST转化为一组机器指令,用来创建一个叫做a的变量(包括分配内存等),并将一个值存储在a中。

1.2理解作用域

为了进一步理解,我们需要多介绍一点编译器的术语。在我们的例子中,引擎会为变量a进行LHS查询。另外一个查找的类型叫做RHS查询。我打赌你一定能猜到“L”和“R”的涵义,它们分别代表左侧和右侧。什么东西的左侧和右侧?是一个赋值操作的左侧和右侧。

换句话说,当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。讲得更准确一点,RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器本身,从而可以对其赋值。从这个角度来说,RHS并不是真正意义上的“赋值操作的右侧”,更准确的说是“非左侧”。

考虑以下代码:

1 console.log(a); 其中对a 的引用是一个RHS引用,因为这里a并没有赋予任何值。相应地,需要查找并取得a的值,这样才能将值传递给console.log(...)。

相比之下,例如:

1 a=2; 这里对a的引用则是一个LHS引用,因为实际上我们并不关心当前的值是什么,只是想要为=2这个值赋值操作找到一个目标。

1.3作用域嵌套

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

考虑以下代码:

1 function foo(a){
2 console.log( a+b );
3 }
4 var b=2;
5 foo( 2 ); //4

对b进行的RHS引用无法在函数foo内部完成,但可以在上一级作用域(在这个例子中就是全局作用域)中完成。

把作用域链比喻成一个建筑:第一层楼代表当前的执行作用域,也就是你所处的位置。建筑的顶层代表全局作用域。LHS和RHS引用都会在当前楼层进行查找,如果没有找到,就会乘坐电梯前往上一层楼,如果还没找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。

1.4异常

为什么区分LHS和RHS是一件重要的事情? 因为在变量还没有声明(在任何作用域中都无法找到该变量)的情况下,这两种查询的行为是不一样的。

考虑如下代码:

1 function foo(a){
2 console.log( a+b );
3 b=a;
4 }
5 foo( 2 );

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

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

严格模式下在行为上有很多不同。其中一个行为就是禁止自动或隐式地创建全局变量。因此,在严格模式下LHS查询失败时,并不会创建并返回一个全局变量,引擎会抛出同RHS查询失败时类似的 ReferenceError异常。

小结:作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用  LHS查询;如果目的是获取变量的值,就会使用    RHS查询。赋值操作符会导致  LHS查询。=操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。js引擎首先会在代码执行前对其进行编译,在这个过程中,像  var  a=2 ;这样的声明会被分解成两个独立的步骤:

1.首先,var   a  在其作用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。

2.接下来,a=2   会查询(LHS查询) 变量a并对其进行赋值。

LHS和RHS查询都会在当前执行作用域开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域(一层楼),最后抵达全局作用域(顶层),无论找到还是没找到都将停止。

不成功的RHS引用会导致抛出   ReferenceError异常,不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出  ReferenceError 异常(严格模式下)。

以上就是本次的内容,如果觉得这篇博文对你有用或者让你了解了一些新知识那就点波推荐吧。本人爱结交朋友,欢迎大家加我的QQ:825348114,一起进步。

你不知道的javaScript上卷(第一章 作用域是什么)的更多相关文章

  1. 读《你不知道的JavaScript&lpar;上卷&rpar;》后感-作用域闭包(二)

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

  2. 读《你不知道的JavaScript&lpar;上卷&rpar;》后感-浅谈JavaScript作用域(一)

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

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

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

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

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

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

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

  6. 你不知道的JavaScript(上)作用域与闭包

    第一部分 作用域与闭包 第一章 作用域是什么 1.作用域 变量赋值操作会执行两个动作:首先编译器会在当前作用域中声明一个变量(如果之前没有声明过), 然后会在运行时引擎会在作用域中查找该变量,找到就会 ...

  7. 你不知道的JavaScript 上卷 2&sol;11

    第一部分——作用域和闭包 第一章 作用域是什么 1.几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个值进行访问或修改.事实上,正是这种储存和访问变量的值的能力将状态带给了 ...

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

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

  9. 《你不知道的JavaScript》第一部分:作用域和闭包

    第1章 作用域是什么 抛出问题:程序中的变量存储在哪里?程序需要时,如何找到它们? 设计 作用域 的目的:为了更好地存储和访问变量. 作用域:根据名称查找变量的一套规则,用于确定在何处以及如何查找变量 ...

随机推荐

  1. 初识Git

    Git是目前世界上最先进的分布式版本控制系统.在Git诞生之前,我们一直使用的是集中式版本控制系统(如CVS.SVN等),那么两者有什么不同呢?分布式的优势又在哪里呢? 分布式vs集中式 集中式版本控 ...

  2. Nginx &plus; spawn-fcgi- Ubuntu中文

    Nginx - Ubuntu中文 页面 讨论 查看源代码 历史   导航 首页 最近更改 随机页面 页面分类 帮助 编辑 编辑指南 沙盒 新闻动态 字词处理 工具 链入页面 相关更改 特殊页面 打印版 ...

  3. 利用 Rational ClearCase ClearMake 构建高性能的企业级构建环境

    转载地址:http://www.ibm.com/developerworks/cn/rational/r-cn-clearmakebuild/ 构建管理是 IBM® Rational® ClearCa ...

  4. opencv--图像轮廓检测

    //图像的轮廓检测上 //By MoreWindows (http://blog.csdn.net/MoreWindows) #include <opencv2/opencv.hpp> u ...

  5. ios 数组排序

    第一种:利用数组的sortedArrayUsingComparator调用 NSComparator  示例: obj1和obj2指的是数组中的对象 //1.数组中存放的是字符 NSComparato ...

  6. springmvc03 非注解和注解处理器映射器和适配器

    1其它非注解处理器映射器和适配器 .1BeanNameUrlHandlerMapping(映射器) 根据请求url(XXXX.action)匹配spring容器bean的 name 找到对应的bean ...

  7. hdu 4738

    桥的应用! 虽然以前做过强联通分量的题,但刷的很水,所以比赛的时候一直想不起来是桥的应用: 反省一下~~~学习一下! 思路,找到权值最小的桥:用tarjin算法! 代码: #include<cs ...

  8. 转:解决方案your project contains error s please fix them before running your application

    文章来自于:http://www.mythroad.net/2013/08/05/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88your-project-contains-e ...

  9. git bash 出现vim的时候怎么退出

    如果是输出状态,首先Esc退出输入状态,然后Shift+;,再输入q!或wq!(不保存改动,wq!是保存文件的写入修改)退出

  10. linux内核的冒险md来源释义# 14raid5非条块读

    linux内核的冒险md来源释义# 14raid5非条块读 转载请注明出处:http://blog.csdn.net/liumangxiong 假设是非条块内读.那么就至少涉及到两个条块的读,这就须要 ...