Chapter 1: What is Scope?

第一章:什么是作用域

One of the most fundamental paradigms of nearly all programming languages is the ability to store values in variables, and later retrieve or modify those values. In fact, the ability to store values and pull values out of variables is what gives a program state.

在几乎所有编程语言中,储存值到变量中和稍后检索或改变这些值都是最基本的能力之一。事实上,这种存储值到变量和将值移除变量的能力才给了程序以“状态”。

Without such a concept, a program could perform some tasks, but they would be extremely limited and not terribly interesting.

没了这个概念的话,一个程序也能完成一些任务,但他们就会有很多地方被限制并且一点都不有趣了。

But the inclusion of variables into our program begets the most interesting questions we will now address: where do those variables live? In other words, where are they stored? And, most importantly, how does our program find them when it needs them?

但是把变量包含到我们的程序中带来的最有趣的问题是:这些变量在哪儿?或者说,他们存储在哪儿?最重要的是,当我们的程序需要这些变量的时候,它是如何找到他们的?

These questions speak to the need for a well-defined set of rules for storing variables in some location, and for finding those variables at a later time. We'll call that set of rules: Scope.

这个问题需要一个定义明确的规则,用于存储变量在某些位置,以及在之后再找出这些变量,我们可以把这个规则叫:作用域

But, where and how do these Scope rules get set?

但是,作用域规则在哪儿设置?怎么设置的?

Compiler Theory

编译原理

It may be self-evident, or it may be surprising, depending on your level of interaction with various languages, but despite the fact that JavaScript falls under the general category of "dynamic" or "interpreted" languages, it is in fact a compiled language. It is not compiled well in advance, as are many traditionally-compiled languages, nor are the results of compilation portable among various distributed systems.

这可能是不言而喻的,或者可能令人惊讶——取决于你融会贯通各种语言的能力,但是尽管JS属于一般范畴的动态型和解释型语言,实际上它却是一个编译型语言。它不是提前编译好的,因为有许多传统编译语言也不是各种分布式编译系统的产物。

But, nevertheless, the JavaScript engine performs many of the same steps, albeit in more sophisticated ways than we may commonly be aware, of any traditional language-compiler.

但是,尽管如此,JS引擎也执行着许多相同的步骤,尽管它使用的是一种更为复杂的方式——比我们可能意识到的任何传统编译语言

In traditional compiled-language process, a chunk of source code, your program, will undergo typically three steps before it is executed, roughly called "compilation":

在传统的编译语言过程中,一块源代码,也就是你的程序,会在执行前遵从典型的‘三步走’,也就是‘编译’

  1. Tokenizing/Lexing: breaking up a string of characters into meaningful (to the language) chunks, called tokens. For instance, consider the program: var a = 2;. This program would likely be broken up into the following tokens: var, a, =, 2, and ;. Whitespace may or may not be persisted as a token, depending on whether it's meaningful or not.

    Note: The difference between tokenizing and lexing is subtle and academic, but it centers on whether or not these tokens are identified in a stateless or stateful way. Put simply, if the tokenizer were to invoke stateful parsing rules to figure out whether a should be considered a distinct token or just part of another token, that would be lexing.

1.分词/词法分析:分词指将一段字符串破成有意义的(相对于这门语言)小块。比如,考虑这段代码:var a=2;这条程序可能会被破成下面的部分:var , a, =,2,还有;  空白可能成为分词小块也可能不会,这得取决于它是否有含义。

注:分词和词法分析之间的区别既微妙又学术,但关键在于这些小块被明确为有状态的还是无状态的。简单点儿说,如果分词块儿调用的是有状态的词法分析规则,来区分a应该作为一个单独的词法块儿还是仅仅是另外一块词法块儿的一部分,那么这个过程就称作词法分析。(我的理解就是 把字符串分为有意义的tokens这是分词,确定每一小块代码段是应该独立还是应该和另外一块合并成一个token,这是词法分析)。

2.Parsing: taking a stream (array) of tokens and turning it into a tree of nested elements, which collectively represent the grammatical structure of the program. This tree is called an "AST" (Abstract Syntax Tree).

The tree for var a = 2; might start with a top-level node called VariableDeclaration, with a child node called Identifier (whose value is a), and another child called AssignmentExpression which itself has a child called NumericLiteral (whose value is 2).

2.解析:取一段分词过的代码流,然后把它变成一个代表了程序语法结构的嵌套元素树,这个树的名字叫AST(Abstract Syntax Tree).

在这个树状结构的解析中,对于var a=2;可能从最高层——变量声明(VariableDeclaration)开始,然后是它的子节点——标识符(Identifier)(它的值是a),已经另外一个子节点AssignmentExpression的子节点叫NumericLiteral(它的值是2)。

3.Code-Generation: the process of taking an AST and turning it into executable code. This part varies greatly depending on the language, the platform it's targeting, etc.

So, rather than get mired in details, we'll just handwave and say that there's a way to take our above described AST for var a = 2; and turn it into a set of machine instructions to actually create a variable called a (including reserving memory, etc.), and then store a value into a.

Note: The details of how the engine manages system resources are deeper than we will dig, so we'll just take it for granted that the engine is able to create and store variables as needed.

3.代码生成:这个过程是使用AST将代码块变为可执行的代码,这部分的过程很依赖于语言本身,包括它的目标平台等。

所以为了避免在细节里太纠结,我们就直接说上述的AST处理了我们的var a = 2;并且把它变成了一行机器指令——这行指令创造出一个变量a,并且存了一个值进去。

注:引擎如何管理系统资源这是一个很深的坑,超出了我们的讨论范围。所以我们只需要知道引擎可以按需求创造出变量并且给它赋值就可以了。

The JavaScript engine is vastly more complex than just those three steps, as are most other language compilers. For instance, in the process of parsing and code-generation, there are certainly steps to optimize the performance of the execution, including collapsing redundant elements, etc.

JS引擎做的工作远比这三步要复杂,比如,在解析和代码生成这两步的过程中,还有一定的步骤去以优化性能的执行,包括折叠冗余元素等。

So, I'm painting only with broad strokes here. But I think you'll see shortly why these details we do cover, even at a high level, are relevant.

所以,我们就言止于此好了,但是你很快就会意识到为什么我们需要关心这个,即使处于一个很高的水平,这些也是息息相关的。

For one thing, JavaScript engines don't get the luxury (like other language compilers) of having plenty of time to optimize, because JavaScript compilation doesn't happen in a build step ahead of time, as with other languages.

还有一件事是js引擎并不像其他语言编译一样有充分的时间去优化,因为js编译并没有像其他语言一样发生在构造之前

For JavaScript, the compilation that occurs happens, in many cases, mere microseconds (or less!) before the code is executed. To ensure the fastest performance, JS engines use all kinds of tricks (like JITs, which lazy compile and even hot re-compile, etc.) which are well beyond the "scope" of our discussion here.

对于js来说,在许多情况下编译发生在执行这段代码前几微秒(或者更少!)的时间里,为了确保最快的性能,js引擎使用了各种技巧,这些都远远超出了我们讨论的“作用域”。

Let's just say, for simplicity's sake, that any snippet of JavaScript has to be compiled before (usually right before!) it's executed. So, the JS compiler will take the program var a = 2; and compile it first, and then be ready to execute it, usually right away.

我们就这么说吧,为了简单起见,任何js代码都会在执行前被编译,所以,js编译器会拿走程序var a = 2,然后先编译它,然后准备去执行它。

You Don't Know JS: Scope & Closures(翻译)的更多相关文章

  1. You Don't Know JS: Scope & Closures (第一章:什么是Scope)

    Content What is Scope? Lexical Scope Function Vs. Block Scope Hoisting Scope Closures Appendix: Dyna ...

  2. You Don't Know JS: Scope & Closures (第4章: Hoisting)

    Chapter4: Hoisting 变量附加到哪个层次的scope,由它们在哪里和如何声明(let, var)来决定. Function scope/Block scope都有相同的法则:任何变量在 ...

  3. You Don't Know JS: Scope & Closures (第3章: 函数 vs 块作用域)

    第二章,作用域由一系列的bubbles组成.每一个都代表了一个container或bucket,装着被声明的identifiers(variables, functions).这些bubbles相互嵌 ...

  4. You Don't Know JS: Scope & Closures (第2章: Lexical Scope)

    2种主要的models for how scope work. 最普遍的是Lexical Scope. 另一种 Dynamic Scope.(在Appendix a中介绍.和Lexical Scope ...

  5. You Don't Know JS: Scope & Closures (附加:Lexical/dynamic作用域)(附加:Lexical-this)

    JavaScript只有Lexical Scope 模式 Lexical Scope就是在写代码的时候,定义函数的时候创建的作用域! 而动态作用域是在runtime时,函数被调用的地方的作用域! 实际 ...

  6. (未完成👃)You Don't Know JS: Scope & Closures (第5章: Scope & Closures)

    Chapter 5: Scope Closure 我们到达这里时,已经对作用域如何工作有了非常健康稳固的理解. 下面,我们转移注意力到一个及其重要,但长期难以理解,几乎是神话中的部分语言:Closur ...

  7. [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...

  8. 网页3D引擎“Babylon.JS”入门教程翻译总结

    使用三个月的业余时间把官方教程的入门部分译为中文并上传到github,在下一步编程前做一个总结. 历程: 最早接触游戏编程是在大三下学期,用汇编语言和实验室里的单片机.触摸屏.电机(提供声效)编的打地 ...

  9. js的closures(闭包)

    JS中的闭包(closure) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面就是我的学习笔记,对于Javascript初学者应该是很有用 ...

随机推荐

  1. CentOS6配置国内yum源

    在安装完CentOS后为了加快安装.更新rpm包的速度.需要将yum源改为国内源,国内比较快的源有中科大.163.sohu源.下面修改为163源为例子: 首先进入源的配置目录:执行 cd /etc/y ...

  2. python学习笔记系列----(六)错误和异常

    python至少有2类不同的错误:语法错误(Syntax Errors)和异常(Exceptions). 8.1 语法错误 这个单词应该还是很有必要认识的,呵呵,语法错误,也叫解析错误,是我们最不愿意 ...

  3. js 小数相加

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat=&qu ...

  4. js 一个自写的 监测类

    自从认识了jQuery后,很多页面加载入口,都放在document.ready里面.但是有时候这个觉得ready加载太慢, 这个[监测类 ]就开始产生了 效果类似这个. 每10毫秒检查一次,直到加载了 ...

  5. C语言三维数组分解

    很多人在学习C的时候,感觉三维数组很难想象,而且不理解深度是什么?做了一个图,帮大家分解一下                                                       ...

  6. 不可错过的炒鸡棒的js迷你库

    小而美被实践是最好用的,这里收藏了一些很好用的js库,他们都功能单一且非常小. COOKIE.JS  https://github.com/js-coder/cookie.js 如果你操作过cooki ...

  7. maven生命周期和插件

    maven生命周期和插件 生命周期 maven的生命周期有三套,互相独立.每个生命周期含有不同阶段,常用如下 clean 清理项目 pre-clean 执行清理前需要完成的工作 clean 清理上一次 ...

  8. 利用反射+AOP,封装Basehandler

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点, ...

  9. 【转】Git图形化界面客户端大汇总

    原文网址:http://my.oschina.net/amstrong/blog/159114 目录[-] 一.TortoiseGit - The coolest Interface to Git V ...

  10. EF INNER JOIN,LEFT JOIN,GROUP JOIN

    IQueryable<TOuter>的扩展方法中提供了 INNER JOIN,GROUP JOIN但是没有提供LEFT JOIN GROUP JOIN适用于一对多的场景,如果关联的GROU ...