天天看点

JQuery之父John Resig带你了解无处不在的JavaScript

本文包括以下内容:

  • JavaScript核心语言特性
  • JavaScript引擎核心要素
  • JavaScript开发中的3个最佳实践

我们先来聊聊Bob。2000年年初,在花了几年时间学习C++桌面应用开发之后,新晋程序员Bob从学校毕业,奔向了软件开发的广阔天地。那个时候,互联网的跨越式发展才刚刚开始。每个公司都想成为下一个亚马逊。有鉴于此,他做的第一件事就是学习网络开发。

最初他用PHP动态生成网页,并在其中穿插JavaScript代码来实现复杂的功能,例如表单验证,甚至是动态的页内计时器。时光如梭,几年之后,智能手机已然成了气候。预见到一个庞大的新兴市场即将形成,Bob决定先行一步,开始学习使用Objective-C和Java来创建运行于iOS和Android上的移动端应用。

几年来,Bob开发了很多成功的应用软件,并且都需要维护和扩展。遗憾的是,日日辗转于不同的编程语言和应用框架之间,可怜的Bob已经筋疲力尽了。

现在我们来谈一下Ann。两年前,Ann在获得软件开发相关的学位后毕业。她的专业方向偏向于网络以及基于云的应用开发。她已经开发出了一些中等规模的网络应用。这些应用基于现代的模型—视图—控制器(Model—View—Controller, MVC)框架,并且还有相应的移动应用供iOS和Android用户使用。她还开发了一款能够同时在Linux、Windows和OS X上运行的桌面应用,甚至着手将其改为完全基于云的无服务器的版本。最重要的是,她所做的所有事情都是通过JavaScript来实现的。

真是一件了不起的事情。Bob花了10年用5种语言才完成的事情,Ann只需要2年以及1种语言就完成了。纵观整个计算机的发展史,还没有哪个特定的知识集合能够如此容易地通行于不同的领域,并发挥作用。

1995年的一项10天内仓促完成的项目,现在却成为了世界上使用最广泛的编程语言之一。JavaScript现在确确实实是无处不在了,这得归功于更强大的JavaScript引擎和一众框架的出现,如Node、Apache Cordova、Ionic和Electron,是它们让这门粗陋的语言冲出了网页的牢笼,飞向了更广阔的空间。此外,如同HTML一样,这门语言本身也正处于期待已久的进化当中,从而被打造成更加适合现代应用开发的语言。

在本文中,我们首先要保证让你了解所有你需要了解的关于JavaScript的内容,这样无论你的情况与Ann还是Bob更为接近,都能够开发各种类型的应用。

你知道吗?

  • Babel和Traceur是什么?为什么它们对现在的JavaScript开发者至关重要?
  • 在网络应用中,什么才是浏览器的JavaScript API的核心组成部分?

1.1 “理解”JavaScript语言

随着职业生涯的发展,许多有着与Bob和Ann类似经历的JavaScript程序员,都到了在工作中运用构成这门语言大部分的元素的阶段。但实际上,很多时候这些技能的运用都处于相当初级的层次。我们对此做出的猜测是,由于JavaScript(采用类似于C语言的语法)有着与其他得到广泛使用的类C语言(比如C#和Java)相近的皮相,从而给人留下了与这些语言相似的印象。

人们总是觉得他们对C#或者Java的了解,能为他们理解JavaScript的工作原理打下坚实的基础。然而这是一个陷阱。与其他主流语言相比,JavaScript函数式语言的血统更多一些。JavaScript中的一些概念从根本上不同于其他的语言。

这些根本性的差异包括以下内容。

  • 函数是一等公民(一级对象)——在JavaScript中,函数与其他对象共存,并且能够像任何其他对象一样地使用。函数可以通过字面量创建,可以赋值给变量,可以作为函数参数进行传递,甚至可以作为返回值从函数中返回。在第3章中我们将花费大量篇幅解释函数,探索它作为第一类对象在编写代码中的好处。
  • 函数闭包——大部分人对闭包都缺乏理解,然而它却从根本上例证了函数之于JavaScript的重要性。尽管就目前而言,了解当函数主动维护了在函数内使用的外部的变量,则该函数为一个闭包就已经足够。现在还没看到闭包的好处也不要紧,第5章中我们会把它搞得一清二楚。除了闭包以外,在第3章和第4章中我们也会深入探讨函数的方方面面,第5章中还会讨论标识符作用域。
  • 作用域——直到最近,JavaScript都还没有(类似C语言中的)块级作用域下的变量,取而代之则只能依赖函数级别的变量和全局变量。
  • 基于原型的面向对象——不同于其他主流的面向对象语言(例如C#、Java、Ruby)使用基于类的面向对象,JavaScript使用基于原型的面向对象。很多开发者是从基于类的面向对象语言(例如Java)转而开发JavaScript,他们试图像开发Java一样开发JavaScript。然而由于某些原因,他们会因为结果与预期不同而感到出乎意料。这种情况就是我们要深入理解原型的原因,我们要知道基于原型的面向对象如何工作,以及怎样在JavaScript中实现面向对象。

对象、原型、函数和闭包的紧密结合组成了JavaScript。理解这些概念的密切联系能大大提高你的编程能力,为你开发各种类型的应用提供坚固的基础,无论你的应用是开发在网页上、桌面应用上、移动应用上还是服务器端。

除了这些基本概念,JavaScript的一些其他功能也能帮你书写优雅高效的代码。对于经验老道的Bob一样的开发者来说,这些部分特性在其他语言中也出现过,例如Java和C++。我们会特别聚焦于以下特性。

  • 生成器,一种可以基于一次请求生成多次值的函数,在不同请求之间也能挂起执行。
  • Promise,让我们更好地控制异步代码。
  • 代理,让我们控制对特定对象的访问。
  • 高级数组方法,书写更优雅的数组处理函数。
  • Map,用于创建字典集合;Set,处理仅包含不重复项目的集合。
  • 正则表达式,简化用代码书写起来很复杂的逻辑。
  • 模块,把代码划分为较小的可以自包含的片段,使项目更易于管理。

深入理解JavaScript的基础知识,以及学习如何最大程度地利用JavaScript的高级特性,能够让你的代码编写水平提升到一个更高的水平。磨炼代码技能、并将这些概念和特性连贯起来也能让你对JavaScript的理解更上一层楼,从而为你编写各种类型的Javscript应用赋予强大的创造力。

1.1.1 JavaScript是如何发展的

ECMAScript语言标准化委员会已经完成了ES7/ES2016版本JavaScript的制定。对于JavaScript(至少相对于ES6而言)ES7是个较小的升级。这是因为委员会的未来目标是每年都能为JavaScript更新较小的改动。

本书中将彻底探索ES6以及ES7的新特性,例如用于处理异步代码的async函数(第6章中会讨论)。

注意

在本文中涉及ES6/ES2015或ES7/ES2016的JavaScript特性时,你将能看到,凡是在提供浏览器是否支持该特性的链接旁边都会有一个这样的图标。
JQuery之父John Resig带你了解无处不在的JavaScript

尽管每年都能增量发布语言新特性是个利好消息,但这并不代表Web开发者能在标准一发布就能立即使用新特性。由于JavaScript代码必须由JavaScript引擎来执行,所以我们必须耐心等待心爱的引擎更新,从而能支持那些令人激动的新特性。

尽管JavaScript引擎开发者也在力求始终保持对最新特性的支持,但开发者还是很可能陷入想使用新特性却还没被支持的困境。

好在你还能通过下列方式https://kangax.github.io/compat-table/es6/、http://kangax. github. io/compat-table/es2016plus/以及 https://kangax.github.io/compat-table/esnext/进行查看,由此保持对浏览器支持状态的了解。

1.1.2 如今的转换编译器已经能让我们体验未来的JavaScript

由于浏览器版本的飞速发布,我们通常不需要等待多久就能等到对JavaScript的支持。但当我们想利用JavaScript的最新特性时,也往往会被残酷的现实绑架:用户依然在使用老旧的浏览器。这时该怎么办?

解决这个问题的方式之一是使用转换编译器transpilers(即“转换器+编译器”,“transformation + compiling”),这类工具能够把最前沿的JavaScript代码转换为等价的(如果不能实现,则使用相似的)能在当前浏览器中运行的代码。

最流行的转换编译器是Traceur和Babel。使用如下教程可以很容易地配置它们:https://github.com/googLe/traceur-compiler/wiki/Getting-stanted或http://babeljs.io/docs/setup。

本书中,我们会主要集中讨论浏览器中的JavaScript代码。为了有效利用浏览器平台,你需要多多实践,学习浏览器的内部原理。让我们开始吧!

1.2 理解浏览器

现如今,JavaScript应用能在很多环境中执行。但是,Java Script最初的运行环境是浏览器环境,而其他运行环境也是借鉴于浏览器环境。本书将重点专注浏览器环境。浏览器提供了多种概念和API让我们来探索,如图1.1所示。

JQuery之父John Resig带你了解无处不在的JavaScript

图1.1 客户端Web应用依赖于浏览器提供的架构。我们主要讨论DOM、

事件、计时器和浏览器API

我们将集中讨论如下概念。

  • 文档对象模型(DOM)——DOM 是Web应用的结构化的UI表现形式,至少最初由Web应用的HTML代码构成。为开发大型应用,你不仅需要深入理解JavaScript 的核心机制,还要学习 DOM 是如何构成的(第2章)以及如何书写有效的DOM操作代码(第12章)。你将学会如何创造高级的、动态的UI。
  • 事件——大部分JavaScript应用都是事件驱动的应用,这表示大部分代码执行在对某个特殊事件响应的上下文中。这样的事件例如网络事件、计时器、用户生成事件例如点击、鼠标移动、键盘按压事件等。因此,第13章中我们将完整探索事件机制。我们特殊关注计时器,计时器通常像个谜团一样,但它能帮我们处理复杂编码任务:例如长期执行的计算和流畅的动画。
  • 浏览器API——帮助我们与世界交互,浏览器提供获取设备的信息、存储本地数据或与远程浏览器交互的API。本书我们会探索其中的一些API。完善编程技能并对浏览器提供的API有深入理解能让你走的更远。但是迟早,你将会遇到浏览器的不一致性等问题。在完美的世界中,所有浏览器都应该没有缺陷,应该都能以一致的方式支持Web标准。然而我们的现实世界并不完美。

近来浏览器的质量已经大大提高了,但我们仍然需要面对一些缺陷:例如缺失的API、某个浏览器的奇怪问题。针对浏览器的这些问题开发出一种易于理解的机制,并搞清楚它们的差异和宽松模式,这与精通JavaScript几乎同等重要。

当我们开发浏览器应用或JavaScript库时,选择支持哪个路蓝旗是很值得深思熟虑的。我们希望全部支持,但受限于开发测试资源要求或其他要求。因此在第14章中,我们将彻底地探索跨浏览器开发的策略。

开发高效的跨浏览器代码显著依赖于开发者的经验和技巧。本书旨在提高开发者技能水平,所以让我们通过当前的最佳实践来开始学习吧。

1.3 使用当前的最佳实践

精通JavaScript语言和掌握跨浏览器代码问题对于专家级Web应用开发者来说是重要课题,但它们不是整个蓝图。若想进入整个联盟,你还需要展示出一些已经被大量先前开发者所证明能够开发出高质量代码的特质。这些特质被称为最佳实践,所以你除了精通JavaScript语言以外,还需要具有以下特质:

  • 调试技巧;
  • 测试;
  • 性能分析。

在编程中把这些技能有效结合在一起非常重要,本书会使用它们。接下来看看这些技巧。

1.3.1 调试

以前,调试JavaScript代码意味着使用alert来验证变量的值。好在,由于Firefox浏览器的开发者扩展Firebug的流行,所以调试JavaScript代码的能力大大增强了。所有主流浏览器的类似工具也都被开发出来:

  • Firebug——开发者扩展工具Firefox的流行成为了调试工具的开端;
  • Chrome DevTools——由Chrome 团队开发,并应用在了 Chrome 和 Opera浏览器中;
  • Firefox开发者工具——包含在Firefox中的工具,由Firefox 团队开发;
  • F12 开发者工具——Internet Explorer 浏览器 及微软 Edge浏览器中包含的调试工具;
  • WebKit 检视器——Safari中包含的调试工具。

如你所见,主流浏览器都为开发者提供了调试Web应用程序的工具。使用alert来调试JavaScript代码的日子一去不复返了!所有这些工具都有着类似于Firebug最初引入的概念,故而它们都提供着相似的功能:探索DOM、调试JavaScript、编辑CSS样式和跟踪网络事件等。其中的每样工具都做得很棒。你既可以使用你自己选择的浏览器所提供的调试工具,也可以使用你发现缺陷时所用的浏览器调试工具。

除此之外,你也可以使用其中的几个工具,例如用Chrome开发者工具来调试其他类型的应用,例如 Node.js应用(在附录B中,我们会向你介绍一些调试技术)。

1.3.2 测试

在本书中,我们会使用一些测试技术来确保示例代码按预期执行,同时这些测试技术也用于展示一般情况下如何测试代码。我们用于测试的主要工具是一个断言函数,其目的在于断定某个假设是真值还是假值。

该函数的一般形式如下所示:

assert(condition, message);

第一个参数是一个应为真值的条件,第二个参数是当断言为假时所展示的一句话。

例如:

assert(a === 1, "Disaster! a is not 1!");

如果变量的值不等于1,则断言失败,然后那段有点儿戏剧性的消息就会被展示出来。

注意

 

断言函数并不是JavaScript的标准特性,所以我们在附录B中会展示它的实现。

1.3.3 性能分析

分析性能是另一个重要实践。尽管JavaScript引擎已经让JavaScript以惊人的效率提升,然而我们依然没有理由书写粗糙低效的代码。

我们会使用如下的代码来收集性能信息:

console.time("My operation");  

⇽--- 开始计时器for(var n = 0; n < maxCount; n++){

 /*perform the operation to be measured*/}  

 ⇽--- 执行多次操作console.timeEnd("My operation");  

 ⇽--- 停止计时器

这段代码中,我们把要被测量的代码放在两个计时器调用之间,分别是内置console对象上的time和timeEnd方法。

在操作开始执行之前,调用console.time启动一个命名计时器(本例中计时器名为 My operation)。然后在特定的循环次数下运行代码(本例中运行maxCount次)。由于一次操作执行太快很难测量,所以我们要多次运行代码从而取得一个能够测量的值。运行次数可以成百上千,甚至上万,其完全依赖于将被测量的代码性质。几次摸索后我们就能得到一个合理的值。

操作结束后则用相同的计时器名字调用console.timeEnd。随后浏览器就会输出从开始到当前的时间差。

把这种技术与前面所学到的最佳实践技术统一起来,你对JavaScript的开发能力就会大幅度提升。在浏览器提供的有限资源下,在浏览器能力和兼容性逐渐复杂的世界中开发应用,需要一套健壮和完整的技巧。

1.4 提高跨平台开发能力

Bob初入Web开发行业时,他会发现每个浏览器都有一套自己的脚本及UI样式的解释方式,并试图鼓吹他们的方式才是最好的方式,这使开发者们沮丧地咬牙切齿。好在浏览器之争以HTML、CSS, DOM、API和JavaScript的标准化而结束,从而开发者能集中精力开发高效的跨浏览器JavaScript应用。确实,集中精力于把网站开发为应用催生了大量的想法、工具和从桌面应用到网站应用的技术。现如今,这些知识和工具的转换再次发生,想法、工具和源于客户端Web开发的技术逐渐渗入应用开发的其他领域。

对JavaScript基本原理和核心API的渗入理解能让你成为更全能的开发者。通过使用浏览器和Node.js(源自于浏览器的环境),你能够开发几乎你能想到的任何类型的应用。

  • 桌面应用,通过使用如NW.js(http://nwjs.io/)或Electron (http://electron.atom.io/)的库可以开发桌面应用。这些技术通常通过包装浏览器使我们能用标准的HTML、CSS和JavaScript(我们可以完全依赖我们的核心JavaScript和浏览器知识来开发)以及一些额外的访问文件系统的能力来构建桌面应用。从而能够开发真正独立于平台的桌面应用,它和我们在Windows、Mac和Linux上见到的应用看起来一样。
  • 移动应用,使用类似Apache Cordova (https://cordova.apache.org/)的框架开发。与使用 Web 技术构建桌面应用一样,该应用框架也包装了浏览器,不过其中还包含一些额外的针对特定平台的API,从而让开发者能与移动平台交互。
  • 使用Node.js开发服务器端应用和嵌入式应用,Node.js是源自于浏览器的环境,使用了很多类似浏览器的底层原理。例如,Node.js 能执行 JavaScript 代码,并且也基于事件驱动。

Ann并不知道自己有多幸运(尽管Bob有个很棒的想法)。无论她是否需要构建一个标准的桌面应用还是移动应用、服务器端应用或嵌入式应用都没问题——所有这些应用都共享同样的标准客户端Web应用底层原理。

只要理解了JavaScript工作的核心原理、理解了浏览器提供的核心API(例如事件,同样与Node.js提供的机制有很多共同点),她就能加速所有应用的开发。在这个过程中,你将变得更全能,知识和理解力也逐步增长,从而能够处理各种各样的问题。你将能够在云上通过使用JavaScript API构建无需依赖服务器的应用,例如使用类似AWS Lamda来部署、维护和控制你应用的云组件。

  • 客户端Web应用作为如今最流行的应用,其概念、工具和技术从仅开发客户端Web应用已经深入到其他应用领域。理解客户端Web应用的基础能帮助你开发一系列不同领域的应用。
  • 为了提高开发技能,你需要深入理解JavaScript的核心机制和浏览器所提供的架构。
  • 本书集中探讨了核心JavaScript的机制,例如函数、函数闭包和原型,还有一些新的JavaScript特性,例如生成器、promise、代理、映射、集合和模块。
  • JavaScript可以在大量的环境中执行,但所有环境的开端是我们将集中探讨的浏览器环境。
  • 除了JavaScript以外,我们还将探索浏览器内部,例如DOM (网页UI的一种结构化表示方式)和事件,这是因为客户端Web应用是事件驱动的应用。

继续阅读