网页书籍必看

所需积分/C币:0 2016-04-21 20:17:22 2.97MB PDF
1
收藏 收藏
举报

网页必看书籍
言 在互联网发展的早期, JavaScript.就已经成为了支撑网页内容交互体验的基础技术。那时 Java Script的作用可能仅仅是生成一些闪烁的鼠标轨迹或者烦人的弹出窗口,但是经过了大约20 年的发展, JavaScript的技术和能力都发生了天翻地覆的变化,现在的 JavaScript毫无疑问已经成 为了世界上使用范围最广的软件平台—互联网——的核心技术。 但是作为一个语言来说,它总是成为大家批评的对象,部分原因是它有很多历史遗留问题,但是主 要原因是它的设计哲学有问题。就像 Brendan eich會经说过的, JavaScript甚至连名字都给人 种“蠢弟弟”的感觉,就像是它更成熱的大哥Java的不完整版本。不过名字只不过是营销策略上的 个意外,这两个语言有许多本质上的区别。 JavaScript和Java的关系,就像 Carnival(嘉年华)和 Car(汽车)的关系一样,八竿子打不着。 JavaScript借鉴了许多语言的概念和语法,比如C风格的过程式编程以及不太明显的 Scheme/List 风格的函数式编程,因此吸引了许多开发者,甚至是那些不会编程的新手。用 JavaScrip来编 写“Hel| lo World"是井常简单的,因此这门语舌很有吸引力并且很好上手。 虽然 JavaScript可能是最早岀现的语言之一,但是由于其本身的特殊性,相比其他语言, 第一部分作用域和闭包 [美] Kyle Simpson著 赵望野译 序 小时候,我特别喜欢把东西拆成雩部件,然后再重新装回去——旧日的移动电话、立体声音响等我能 拿到的一切物件都没能幸免。对于年幼的我来说,使用这些东西还为时过早,但是一旦它们坏了, 我就立刻想弄清楚它们的工作原理。 记得有一次,我看见一个老式收音机的电路板,其中有一个缠满铜线的奇怪长管。我不知道这个长 管的用途,所以立刻开始研究它。它有什么用?为什么出现在收音机里?为什么它看起来和电路板 的其他部分不一样?为什么会有铜线缠绕着它?如果我把铜线拆下来会发生什么?现在我知道了, 这是一个在晶体管收音机中很常见的、由缠绕着铜线的铁氧体棒制成的环形天线。 你是否也會对解答各种各样的为什么很上瘾?大多数孩子都会。事实上,这可能是孩子身上我最喜 欢的地方—求知欲很强。 很遗憾,现在我从事着一份专业性的工作,并以制作一些东西来度日。而我儿时的梦想是有一天能 够制作那些被我拆开过的东西。当然,现在我所制作的大部分东西都是用 Java Script做成的,而不 是铁氧体棒.…但它们很相似!尽管我會经一度非常热爱制作东西,但是现在却更渴望了解事物的 运行原理。我经常寻找解决问题或修复bug的最佳方法,却很少花时间来研究我所使用的工具。 这也是为什么我一看到你不知道的 JavaScript"系列图书就很激动,因为 JavaScript的确有很多我 不了解的地方。我每天从早到晚都在使用 JavaScript,并且已经持续了好几年,但我真的了解它了 吗?答案是否定的。当然,我了解它的很多细节,并且经常阅读标准文档和邮件列表中的内容,但是 了解的程度低于我内心那个六岁的孩子希望我达到的水平。 第一部分“作用域和闭包”是一个非常好的切入点。它对于如我一般的受众来说非常有用(希望对你 也同样有用)这本书并不会教你如何使用 JavaScript,但是它会让你意识到对于其内部的运行原 理你可能了解得并不多。同时这本书出现的时机也非常巧:ES6终于稳定下来了,并且各家浏览器 的实现工作也正在逐步展开。如果你还没有学习其中的新功能(比如1et和 const),这本书将起到 很好的介绍作用。 所以我希望你能喜欢这本书,尤其希望Kye对 JavaScript工作原理每一个细节的批判性思考会渗 透到你的思考过程和日常工作中。知其然,也要知其所以然。 Shane hudson www.shanehudson.net 第1章作用域是什么 几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个值进行 访问或修改。事实上,正是这种储存和访问变量的值的能力将状态带给了程序。 若没有了状态这个概念,程序虽然也能够执行一些简单的任务,但它会受到高度限制,做不到并常 有趣。 但是将变量引入程序会引起几个很有意思的问题,也正是我们将要讨论的:这些变量住在哪里?换 句话说,它们储存在哪里?最重要的是,程序需要时如何找到它们? 这些问题说明需要一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。这套规 则被称为作用域。 但是,究竟在哪里而且怎样设置这些作用域的规则呢? 1.1编译原理 尽管通常捋 Java script归类为“动态”或“解释执行语言,但事实上它是一门编译语言。这个事实对 你来说可能显而易见,也可能你闻所未闻,取决于你接蝕过多少编程语言,具有多少经验。但与传 统的编译语詈不同,它不是提前编译的,编译结果也不能在分布式系统中进行移植。 尽管如此, JavaScript引擎进行编译的步骤和传统的编译语舌非常相似,在某些环节可能比预想的 要复杂。 在传统编译语言的流程中,程序中的一段源代码在执行之前会经历三个步骤,统称为“编译”。 分词/词法分析( Tokenizing/ Lexing) 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被 称为词法单元( token)。例如,考虑程序vara=2;这段程序通常会被分解成为下面这些词法 单元:ar、a、三、2、;空格是否会被当作词法单元,取决于空格在这门语舌中是否具有意义。 A分词( okenizing)和词法分析( Lexing)之间的区别是非常微妙、晦涩的,主要差异在于词 法单元的识别是通过有状态还是无状态的方式进行的。简单来说,如果词法单元生成器在半 断a是一个独立的词法单元还是其他词法单元的一部分时,调用的是有状态的解析规则,那么 这个过程就被称为词法分析。 解析语法分析( Parsing) 这个过程是捋词法单元流(数组)转换成一个由元秦逐级嵌套所组成的代表了程序语法结构的 树。这个树被称为“抽象语法树”( Abstract Syntax Tree,AST)。 vara=2;的抽象语法树中可能会有一个叫作 Variabledeclaration的顶级节点,接下来是一个 叫作 Identifier(它的值是a)的子节点,以及一个叫作 AssIgnmentExpression的子节 点。 AssignmentExpression节点有一个叫作 Numericlitera1(它的值是2)的子节点。 代码生成 捋AST转换为可执行代码的过程称被称为代码生成。这个过程与语言、目标平台等息息相关。 抛开具体细节,简单来说就是有某种方法可以将vara=2;的AST转化为一组机器指爷,用来 创建一个叫作a的变量(包括分配内存等),并将一个值储存在a中。 关于引擎如何管理系统资源超岀了我们的讨论范围,因此只需要简单地了解引擎可以根 据需要创建并储存变量即可。 比起那些编译过程只有三个步骤的语言的编译器, Java Script引擎要复杂得多。例如,在语法分析 和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等。 因此在这里只进行宏观、简单的介绍,接下来你就会发现我们介绍的这些看起来有点高深的内容 与所要讨论的事情有什么关联。 首先, Javascript引擎不会有大量的(像其他语言编译器那么多的)时间用来进行优化,因为与其他 语言不同, JavaScript的编译过程不是发生在构建之前的。 对于 JavaScript来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短!)的时间内。在我 们所要讨论的作用域背后, Java Script引擎用尽了各种办法(比如JT,可以延迟编译甚至实施重编 译)来保证性能最佳。 简单地说,任何 JavaScript代码片段在执行前都要进行编译(通常就在执行前)。因此, JavaScript编 译器首先会对vara=2;这段程序进行编译,然后做好执行它的准备,并且通常马上就会执行它。 1.2理解作用域 我们学习作用域的方式是捋这个过程模拟成几个人物之间的对话。那么,由谁进行这场对话呢? 1.21演员表 首先介绍将要参与到对程序vara=2;进行处理的过程中的演员们,这样扌能理解接下来捋要听 到的对话。 引擎 从头到尾负责整个 JavaScript程序的编译及执行过程。 编译器 引擎的好朋友之一,负责语法分析及代码生成等脏活罴活(详见前一节的内容)。 作用域 引擎的另一位好朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施 套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。 为了能够完全理解 Javascript的工作原理,你需要开始像引擎(和它的朋友们)一样思考,从它们的 角度提出问题,并从它们的角度回答这些问题。 122对话 当你看见vara=2;这段程序时,很可能认为这是一句声明。但我们的新朋友引擎却不这么看。事 实上,引擎认为这里有两个完全不同的声明,一个由编译器在编译时处理,另一个则由引擎在运行 时处理。 下面我们将vara=2;分解,看看引擎和它的朋友们是如何协同工作的。 编译器首先会将这段程序分解成词法单元,然后将词法单元解析成一个树结构。但是当编译器开 始进行代码生成时,它对这段程序的处理方式会和预期的有所不同。 可以合理地假设编译器所产生的代码能够用下面的伪代码进行概括:“为一个变量分配內存,捋其 命名为a,然后将值2保存进这个变量。”然而,这并不完全正确。 事实上编译器会进行如下处理。 1.遇到vara,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中。 如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作用域的集合中声明· 个新的变量,并命名为a。 2.接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a=2这个赋值操作。引擎 运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作a的变量。如果否,引擎就会 使用这个变量;如果不是,引擎会继续查找该变量(查看1.3节)。 如果引擎最终找到了a变量,就会将2赋值给它。否则引擎就会举手示意并拋出一个异常! 总结:变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没 有声明过),然后在沄行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。 123编译器有话说 为了进一步理解,我们需要多介绍一点编译器的术语。 编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过査找变量a来判断它是否已声明 过。査找的过程由作用域进行协助,但是引擎执行怎样的査找,会影响最终的查找结果。 在我们的例子中,引擎会为变量a进行LHS查询。另外一个查找的类型叫作RHS。 我打赌你一定能猜到L”和“R”的含义,它们分别代表左侧和右侧。 什么东西的左侧和右侧?是一个赋值操作的左侧和右侧 换句话说,当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。 讲得更准确一点,RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量 的容器本身,从而可以对其赋值。从这个角度说,RHS并不是真正意义上的“赋值操作的右侧”,更准 确地说是“非左侧”。 你可以将RHS理解成 retrieve his source value(取到它的源值),这意味着“得到某某的值”。 让我们继续深廴研究。 考虑以下代码: console. log( a) 其中对a的引用是一个RHS引用,因为这里a并没有赋予任何值。相应地,需要查找并取得a的值,这 样扌能将值传递给 console.1og()。 相比之下,例如: a=2 这里对a的引用则是LHS引用,因为实际上我们并不关心当前的值是什么,只是想要为=2这个赋 值操作找到一个目标。 LHS和RHs的含义是“赋值操作的左侧或右侧”并不一定意味着就是“赋值操作符的左侧 或右侧冖。赋值操作还冇其他几种形式,因此在穊念上最好烀其理解为“赋值操作的目标是谁 (LHS)”以及“谁是赋值操作的源头(RHS)"。 考虑下面的程序,其中既有LHS也有RHS引用: function foo(a) t console. log( a)i//2 foo( 2) 最后一行foo(.)函数的调用需要对foo进行RHS引用,意味着“去找到foo的值,并把它给我”。并 且(.)意味着foo的值需要被执行,因此它最好真的是一个函数类型的值! 这里还有一个容易被忽略却非常重要的细节。 代码中隐式的a=2操作可能很容易被你忽略掉。这个操作发生在2被当作参数传递给foo(..)函数 时,2会被分配给参数a。为了给参数a(隐式地)分配值,需要进行一次LHS查询 这里还有对a进行的RHS引用,并且捋得到的值传给了 conso1e,10g(.)。 console.10g(.)本身也需 要一个引用扌能执行,因此会对 console对象进行RHS查询,并且检查得到的值中是否有一个叫 作10g的方法。 最后,在概念上可以理解为在LHS和RHS之间通过对值2进行交互来将其传递进10g(.)(通过变 量a的RHS查询)。假设在1g(.)函数的原生实现中它可以接受参数,在将2赋值给其中第一个(也 许叫作arg1)参数之前,这个参数需要进行LHS引用查询 A你可能会倾向于将函数声明 function foc(a){.,概念化为普通的变量声明和赋值,比 如 var foc(、foo= function(a){.。如果这样理解的话,这个函数声明捋需要进行LHS查询。 然而还有一个重要的细微差别,编译器可以在代码生成的同时处理声明和值的定义,比如在引 擎执行代码时,并不会有线程专门用来将一个函数值“分配给"foo。因此,捋函数声明理解成前 面讨论的LHS查询和赋值的形式并不合适。 1.24引擎和作用域的对话 function foo(a)t console. log( a i//2

...展开详情
试读 127P 网页书籍必看
立即下载 低至0.43元/次 身份认证VIP会员低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
  • 签到新秀

    累计签到获取,不积跬步,无以至千里,继续坚持!
  • 分享宗师

    成功上传21个资源即可获取
关注 私信
上传资源赚积分or赚钱
最新推荐
网页书籍必看 0积分/C币 立即下载
1/127
网页书籍必看第1页
网页书籍必看第2页
网页书籍必看第3页
网页书籍必看第4页
网页书籍必看第5页
网页书籍必看第6页
网页书籍必看第7页
网页书籍必看第8页
网页书籍必看第9页
网页书籍必看第10页
网页书籍必看第11页
网页书籍必看第12页
网页书籍必看第13页
网页书籍必看第14页
网页书籍必看第15页
网页书籍必看第16页
网页书籍必看第17页
网页书籍必看第18页
网页书籍必看第19页
网页书籍必看第20页

试读结束, 可继续阅读

0积分/C币 立即下载 >