0%

EJ13

JavaScript和浏览器

这本书的下一张将会讨论web浏览器。没有web浏览器,就不会有JS。或者即使有,也没有人会关注它。

web技术从一开始就是分散的,不仅在技术上,它发展的方式也是一样。各种浏览器厂商都以一些特别的、有时考虑不周的方式添加了新功能,这些功能有时会被其他厂商采用,并最终以标准的形式确定下来。

这既是一种祝福,也是一种诅咒。一方面,它允许没有中央方控制一个系统,而是由各方在松散的协作(或偶尔公开的敌对状态下)下进行改进。另一方面,Web开发的随意方式意味着最终的系统并不是内部一致性的光辉典范。它的某些部分完全令人困惑,构思拙劣。

网络和Internet

计算机网络早在20世纪50年代就出现了。如果你在两个或者多个计算机间放置电缆并且允许它们来回通过这些电缆发送数据,你就可以做各种各样精彩的事情。

如果连接在一栋大楼里面的两个计算机允许我们做精彩的事,那么将整个星球的计算机互联会更棒。开始实现这个愿景的技术在20世纪80年代被开发出来,最终导致的网络被叫做Internet。它没有辜负它的诺言。

一台计算机可以向另外的计算机发送bit。为了从这种bit-shooting模式中产生高效的通信,双方计算机必须知道bit应该代表什么。任何给定序列的bit的含义完全取决于要表达的东西以及使用的编码机制。

一个网络协议描述了一种通过网络通信的方式。有发送电子邮件,收电子邮件,共享文件,甚至是控制那些刚好被恶意软件感染的计算机的各种各样的协议。

例如,超文本传输协议(HTTP)就是一个用于检索命名资源(一块信息,例如网页或者图片)的协议。它指定发起请求的一方应该像下面这样开始一个请求,指定资源名字和要使用的协议版本。

1
GET /index.html HTTP/1.1

关于请求方在请求中包含更多信息的方式和接收方打包返回内容的方式有各种各样的规则。我们将在18章深入学习HTTP。

大多数的协议在其他协议之上构建。HTTP将网络看作类似流一样的设备,你可以将bit放入其中,并且让他们以正确的顺序到达正确的终点。如同我们在11章看到的那样,确保这些并不是容易的事。

传输控制协议(TCP)是一个解决这个问题的协议。所有联网的设备使用这种协议,并且大多数的互联网通信都构建在这种协议之上。

一个TCP连接像下面这样工作:一台计算机必须等待,或者监听其他计算机来发起通信。为了能够在一台计算机上同时监听不同种类的通讯,每一个监听器关联一个数字(端口号)。大多数的协议指定默认端口号。例如,当我们想要使用SMTP发送邮件的时候,我们发送电子邮件的计算机将监听25端口。

另一台计算机然后就可以通过用正确的端口号连接到目标计算机来建立连接。如果目标机器可达并且正在监听那个端口,连接就成功创建了。监听的计算机叫做服务器,而发起连接的计算机叫做客户端。

这样的连接表现的就像可以flow bit的双向管道——彼此都可以向上面发送数据。一旦bit发送成功,它们就可以再次在另一端读取。这是一个方便的模型。你可以说TCP提供了网络的抽象。

Web

万维网(不要和作为整体的Internet搞混)是一组允许我们在浏览器中访问网页的一组协议和格式。名称中的web指的是这样的网页可以很容易的连接到彼此,因此连接成了用户可以在其中移动的巨大网格。

为了成为万维网的一部分,你需要做的就是将一台机器连接到互联网,并让它用HTTP协议监听80端口,这样其他计算机就可以向它索要文档。

每一个web上的文档都以统一资源定位符(URL)命名,看起来像这样:

1
2
3
http://eloquentjavascript.net/13_browser.html
| | | |
protocol server path

第一部分告诉我们这个URL使用了HTTP协议(对比加密的HTTP,应该是https://)。然后是我们要请求的文档来自哪个server。最后是标识我们感兴趣的特定文档(或者资源)的路径字符串。

连接到互联网的计算机得到一个IP地址,是一个可用于发送消息到该计算机的数字,看起来像这样149.210.142.219或者2001:4860:4860::8888。但是或多或少的随机数列表很难记忆并且不容易输入,所以你可以为一个特定地址或者一个地址集合注册一个域名。我注册了eloquentjavascript.net这个域名指向我控制的计算机的IP地址并且因此可以使用这个域名来提供网页。

如果你将URL输入浏览器的地址栏,浏览器将尝试检索并显示那个URL地址的文档。首先,你的浏览器必须找到地址eloquentjavascript.net指向的地址。然后,使用HTTP协议,将会向那个地址的服务器请求一个连接并请求资源*/13_browser.html*。如果一切顺利,服务器发送回来一个文档,浏览器将其显示在屏幕上。

HTML

HTML,代表超文本标记语言,是用于网页的文档格式。一个HTML文档除了给出文本结构的标签,用于描述链接,段落和标题等,还包括文本。

一个HTML文档可能看上去像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>My home page</title>
</head>
<body>
<h1>My home page</h1>
<p>Hello, I am Marijn and this is my home page.</p>
<p>I also wrote a book! Read it
<a href="http://eloquentjavascript.net">here</a>.</p>
</body>
</html>

包裹在尖括号(<>)的标签,提供关于文档结构的信息。其他的文本就是普通的文字。

文档以<!doctype html>开头,告诉浏览器将这个页面解释位现代HTML,不同于使用在过去的各种各样的方言。

HTML文档有一个head和一个body。head包含关于文档的信息,body包含文档本身。在这个例子中,head声明了文档的标题为”My home page”,并且使用UTF-8编码,这是一种将Unicode文本编码为二进制数据的方式。文档的body包含了标题和两个段落。

标签以多种形式出现。一个元素,如body,一个段落或者一个链接,开始于opening tag像<p>,并终止于closing tag像</p>。一些opening tag,例如链接的那个,以name=”value”的形式包含额外的信息。这些被叫做属性。在这个例子中,连接的终点用href=”http://eloquentjavascript.net"来表示,href代表hypertext reference。

一些标签不包含任何东西因此不需要闭合。元标签<meta charset="utf-8">就是这样的例子。

为了能够在文档的文本中包含尖括号,即使它们在HTML中有特殊的含义,另一种形式的特殊标记必须引入。一个普通的开始尖括号写作&lt;,一个关闭尖括号写作&gt;。HTML中,&符号后面跟着一个名字或者字符代码和一个分号被叫做实体(entity),并会由它编码的字符代替。

这类似于JS中反斜线使用的方式,因为这种机制也给了&符号一个特殊的意义,它们就需要被转义为&amp;。在包装在双引号的属性值中,&quot;可以被用于插入一个实际的引号字符。

HTML以一种极度能容忍错误的方式解析。当应该在的标签丢失的时候,浏览器重新构建他们。以何种方式实现已经被标准化了,所以你可以在现代浏览器中依赖这个。

下面的文档将会和刚刚的文档一样看待。

1
2
3
4
5
6
7
8
9
<!doctype html>

<meta charset=utf-8>
<title>My home page</title>

<h1>My home page</h1>
<p>Hello, I am Marijn and this is my home page.
<p>I also wrote a book! Read it
<a href=http://eloquentjavascript.net>here</a>.

<html><head><body>标签完全丢失了。浏览器知道<meta><title>在head中并且<h1>意味着bidy开始了。此外,我没有明确关闭一个段落,因为开始一个新的段落或者结束文档将隐式闭合它们。属性值的引号也省略了。

这本书经常会忽略<html><head><body>标签来使得行文简洁而不过分杂乱。但是我将会闭合标签并且在属性周围包含引号。

我也经常会忽略doctype和charset声明。并不鼓励你从HTML文档中忽略这些。当你丢弃这些的时候浏览器通常会做一些荒谬的事情。即便doctype和charset没有明确展示在文本中,你也应该隐式默认它们在。

HTML和JavaScript

在这本书的上下文中,最重要的HTML标签就是<script>。这个标签允许我们在文档中包含一段JS代码。

1
2
<h1>Testing alert</h1>
<script>alert("hello!");</script>

当浏览器读取HTML的时候一遇到script标签这个script就会立刻运行。这个页面会弹出一个对话框——alert类似prompt,在弹窗这方面,但是不会询问输入。

直接在文档中嵌入大型程序通常不切实际。<script>标签可以通过src属性从一个URL获取一个script文件。

1
2
<h1>Testing alert</h1>
<script src="code/hello.js"></script>

code/hello.js包含了同样的程序——alert("hello!")。当HTML页面引用其他的URL作为自己的一部分时——如一个图片或者一个script——浏览器将立刻检索它们并将其包含到页面中。

一个script标签必须总是以</script>关闭,即使他引用不包含任何代码的script文件。如果你忘记这个,页面的剩余部分都会被解释为script的一部分。

可以在浏览器中通过给script一个type="module"属性来加载ES模块(参见第十章)。这样的模块可以通过在import声明中使用相对于他们的URL作为模块名来依赖其他模块。

一些属性也可以包含一个JS程序。下面展示的<button>标签(作为按钮展示)有一个onclick属性。当按钮被点击时属性值运行。

1
<button onclick="alert('Boom!');">DO NOT PRESS</button>

注意我在onclick属性中的字符串使用了单引号,因为双引号已经被用于引用整个属性了。我也可以用&quot;

在沙箱中

运行从互联网上下载的程序具有潜在的危险性。你不太了解你所访问网站背后的人,他们也不一定是善意的。运行非善意人写的程序容易让你的电脑被病毒感染,你的数据被偷,并且你的账户被黑客攻击。

尽管web的吸引力就是你可以不需要信任你所访问的所有页面的浏览它。这就是为什么浏览器极大限制了JS程序可以做的事情:他不能访问你计算机的文件或者修改任何与JS嵌入网页无关的任何东西。

以这种方式隔离一个编程环境叫做沙盒化(sandboxing)。

沙盒最困难的部分在于允许程序有足够有用的空间同时还限制它们做危险的事情。许多有用的功能,如和其他服务器通信或者读取剪切板的内容,也可以被用于做有问题,侵犯隐私的事情。