近几天看了一本不错的 JavaScript 的书,是 Kyle Simpson 写的 <You Don't know JS>。这本书是 Kyle Simpson 在 Github 上的开源项目,截止到现在已经有 27,796 个 star 。本想看英文版本,不料在某东上看到了中文版,于是乎就买下了。结果,翻译得还不错,推荐。

原著github地址 ,某东链接自行搜索呵呵。

这本书属于JavaScript开发者的进阶读物,原著至今为止已经出了6本,中文版(上卷)涵盖了其中的两本,介绍了4个知识点,分别为作用域、闭包、this和原型继承。

看完了作用域和闭包部分,以前对这块有很多不大理解的地方,我觉得现在清晰了很多。虽然有很多概念先前已经有所耳闻,比如说作用域、变量提升等,但始终停留在知其然而不知所以然的程度。但此书用简单的例子从相对比较底层的角度解释这些概念,着实为我打开了新世界的大门,总之是相见恨晚!

以下是我认为受益良多的部分:


1. 编译器、引擎和作用域的关系

我没有软件工程专业学位,在读这本书之前,我并不知道编译器、引擎是什么。当然,这本书也不是一本介绍编译器和引擎的书,但是至少到现在我知道了它们在大概是做什么的,以及在运行你写的代码的时候它们扮演了什么角色。

简单来说,编译器会事先拿到你的代码,然后把它们拆开,然后重组成特定的结构,再转换成计算机能够读懂的形式交给引擎,然后引擎会运行这些机器指令。由于JavaScript是一门 动态的、解释执行 的语言,编译发生在代码块执行前的极短时间内,这个过程可能会和传统语言有所出入,但是大同小异。

而作用域和编译器与引擎有什么关系?关系很大。 因为引擎执行一段代码之前,需要知道变量相关的情况。因为引擎需要弄清楚变量属于哪个作用域,这样引擎才能够对变量进行赋值等操作。

另外:变量查询分为两种:LHS查询 和 RHS查询 (分别代表Left和Right)。什么是LHS和RHS?如果查找的目的是对变量进行赋值,就会用到LHS;如果目的是获取变量的值,就是RHS。


2. 词法作用域和欺骗词法

好的,假设你已经在别的地方获知了作用域这个概念。那 词法作用域 是啥?

原来作用域分为 词法作用域 和 动态作用域。

词法作用域 就是在书写的时候就确定了的,而 动态作用域 是在函数被调用的时候确认的。观察一下的例子:

```
function foo() {
console.log(a);
} function bar() {
var a = 3;
foo();
} var a = 2; bar();
```
  • 如果是词法作用域,结果会是 2。

    由于词法作用域是书写时确定的,那么作用域就会根据 书写的位置 确定。在这个例子中,console.log() 查询 a 变量的时候,在 foo() 作用域内部查找不到 a 标识符,就会向外部的作用域查询,也就是 window.a 啦。

  • 如果是动态作用域的话,结果会是 3。

    动态作用域不关心函数是在何处声明的,只关心它是在何处被调用的。这个例子中,console.log() 查询 a 变量的时候,同样在 foo() 作用域内部查找不到 a 标识符。但是它会根据 foo() 被 调用的位置 来查找外部作用域,也就是 bar() 啦。所以这里会输出3。

总之,一句话: 词法作用域只关心函数是在何处声明的,而动态作用域只关心函数是在哪里被调用的。JavaScript并没有动态作用域,但是可以用 this、.apply()、.call()机制来实现动态作用域的效果。


3. 块级作用域

传统编程语言会有块作用域的概念,通常由大括号 {} 包住的诸如for 和 if这些都会创建块作用域。

JavaScript并不是这样的。

来,我们回顾一下这个经典的案例:

for (var i = 0; i < 10; i++) {
console.log(i);
}

因为JavaScript没有块作用域,这时候 i 会污染全局作用域。所以通常建议这样写:

var i;
for (i = 0; i < 10; i++) {
console.log(i);
}

起码这样视觉上更加突出 i 污染了全局作用域的事实(笑)。那是不是说明JavaScript并没有快作用域?不是的。

实际上,with 和 try...catch 的 catch 分句会创建一个块作用域。

除此之外,ES6的 let 关键字会把变量锁定在块里面(真是不错啊)。另外一点需要注意的是使用 let 声明的变量并不会被提升。


4. 变量提升与函数提升

还是书中的例子:

console.log(a);

var a = 2;

请问结果是什么?答案是 undefined。前几天我刚在别的地方看到过这个问题,现在我懂了。

根据上述编译的原理。JavaScript会把代码中的声明都找出来,以把它们归为相应的作用域。所以说,这些声明是会在执行其他代码之前处理过的。

实际上,变量包括函数声明都会被提升到 相应作用域 之前运行。在以上例子中,实际上执行起来的顺序看起来是这样的:

var a;

console.log(a);

a = 2;

所以,结果是 undefined。

另外,我有一点猜测,没有证实过不知道对不对。LHS查询失败都会报ReferenceError,RHS查询不到值都会输出undefined。


5. 闭包

闭包是什么? 以下这句话能够很好的阐释闭包:

当函数可以记住并访问所在的词法作用域,即使函数是当前词法作用域之外执行,这时就产生了闭包。

可见,同时满足以下条件的实体才能够形成闭包:

1. 引用了外部作用域的变量(数据)

2. 在定义词法作用域以外被调用

(未完)

<你不知道的JavaScript>读书笔记的更多相关文章

  1. csapp读书笔记-并发编程

    这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...

  2. CSAPP 读书笔记 - 2.31练习题

    根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1)  属于第一种情况 sum = x ...

  3. CSAPP读书笔记--第八章 异常控制流

    第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...

  4. CSAPP 并发编程读书笔记

    CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  7. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  8. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  9. C#刨根究底:《你必须知道的.NET》读书笔记系列

    一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...

  10. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

随机推荐

  1. windows7开启虚拟wifi和虚拟无线AP的方法

         你可以开启windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP),就可以让电脑变成无线路由器,实现共享上网. 1.点开始  所有程序   命令提示符右键管理员身份运行命令 ...

  2. leetcode@ [208] Implement Trie (Prefix Tree)

    Trie 树模板 https://leetcode.com/problems/implement-trie-prefix-tree/ class TrieNode { public: char var ...

  3. Ubuntu 固态硬盘 4K对齐及启用 Trim,及其验证方法

    因为之前一个移动硬盘因为坏道蔓延导致没办法继续使用,我略冲动地跑去买了一块 120GB 的三星840 固态硬盘回来.为了使用起来更方便,还去弄了个光驱位硬盘托架,把固态硬盘接在了光驱位与原本的笔记本硬 ...

  4. 从assemblyer Instructure deepth understander C principle

    要彻底搞清楚C语言的原理,就必须深入到指令一层去理解.你写一行C代码,编译器会生成什么样的指令,要做到心中有数;

  5. A Tour of Go Exercise: Maps

    Implement WordCount. It should return a map of the counts of each “word” in the string s. The wc.Tes ...

  6. jquery validation 简单验证手机号码

    js代码 // 手机号码验证 jQuery.validator.addMethod("isMobile", function(value, element) { var lengt ...

  7. Android设计模式系列--观察者模式

    观察者模式,是一种非常常见的设计模式,在很多系统中随处可见,尤其是涉及到数据状态发生变化需要通知的情况下.本文以AbstractCursor为例子,展开分析.观察者模式,Observer Patter ...

  8. kvm上安装xp

    主要为了看看图像显示是否有问题,跑起来系能如何,网络连接.文件共享是怎样的. 用的是雨林木风xp sp3的iso.为了提高性能,决定使用qcow2格式,预分配metadata,cache=none(查 ...

  9. [React Native] Using the Image component and reusable styles

    Let's take a look at the basics of using React Native's Image component, as well as adding some reus ...

  10. 全面解析java注解

    一.注解概述       1.学习注解能够读懂别人的代码,特别是框架相关的代码       2.让自己的编程更加简洁,代码更加清晰       3.让别人高看一眼,会使用自定义注解来解决问题     ...