元数据

JavaScript高级程序设计(第3版)

  •  JavaScript高级程序设计(第3版)|200
  • 书名: JavaScript高级程序设计(第3版)
  • 作者: Nicholas C.Zakas
  • 简介: 本书是JavaScript超级畅销书的新版。ECMAScript 5 和HTML5在标准之争中双双胜出,使大量专有实现和客户端扩展正式进入规范,同时也为JavaScript增添了很多适应未来发展的新特性。本书这一版除增加5 章全新内容外,其他章节也有较大幅度的增补和修订,新内容篇幅约占三分之一。全书从JavaScript语言实现的各个组成部分——语言核心、DOM、BOM、事件模型讲起,深入浅出地探讨了面向对象编程、Ajax 与Comet服务器端通信,HTML5表单、媒体、Canvas(包括WebGL)及Web Workers、地理定位、跨文档传递消息、客户端存储(包括IndexedDB)等新API,还介绍了离线应用和与维护、性能、部署相关的最佳开发实践。本书附录展望了未来的API和ECMAScript Harmony规范。 本书适合有一定编程经验的Web应用开发人员阅读,也可作为高校及社会实用技术培训相关专业课程的教材。
  • 出版时间 2012-03-27 00:00:00
  • ISBN: 9787115275790
  • 分类: 计算机-编程设计
  • 出版社: 人民邮电出版社
  • PC地址:https://weread.qq.com/web/reader/eb232f50718ff5e9eb2a999

高亮划线

前言

📌 本书不适合没有计算机基础知识的初学者,也不适合只想为网站添加简单交互功能的读者。建议这些朋友学习阅读Beginning JavaScript,3rd Edition(Wiley,2007)一书[插图]。 ⏱ 2020-12-01 09:38:26

第1章 JavaScript简介

📌 它的主要目的是处理以前由服务器端语言(如Perl)负责的一些输入验证操作 ⏱ 2020-12-01 09:54:26

📌 如今,JavaScript的用途早已不再局限于简单的数据验证,而是具备了与浏览器窗口及其内容等几乎所有方面交互的能力。 ⏱ 2020-12-01 09:54:38

1.2 JavaScript实现

📌 虽然JavaScript和ECMAScript通常都被人们用来表达相同的含义,但JavaScript的含义却比ECMA-262中规定的要多得多。 ⏱ 2020-10-14 12:34:58

📌 ECMA-262定义的只是这门语言的基础,而在此基础之上可以构建更完善的脚本语言。 ⏱ 2020-10-31 22:41:03

📌 宿主环境不仅提供基本的ECMAScript实现,同时也会提供该语言的扩展,以便语言与环境之间对接交互。而这些扩展——如DOM,则利用ECMAScript的核心类型和语法提供更多更具体的功能,以便实现针对环境的操作。 ⏱ 2020-10-16 11:51:35

📌 文档对象模型(DOM, Document Object Model)是针对XML但经过扩展用于HTML的应用程序编程接口(API, Application Programming Interface)。 ⏱ 2020-10-14 12:34:58

📌 DOM把整个页面映射为一个多层节点结构。HTML或XML页面中的每个组成部分都是某种类型的节点 ⏱ 2020-10-14 12:34:59

📌 如果不对Netscape和微软加以控制,Web开发领域就会出现技术上两强割据,浏览器互不兼容的局面。此时,负责制定Web通信标准的W3C(World WideWebConsortium,万维网联盟)开始着手规划DOM。 ⏱ 2020-12-01 11:04:12

📌 DOM1级由两个模块组成:DOM核心(DOM Core)和DOM HTML ⏱ 2020-12-01 11:04:23

📌 那就是支持可以访问和操作浏览器窗口的浏览器对象模型(BOM, Browser Object Model) ⏱ 2020-12-01 11:18:59

📌 开发人员使用BOM可以控制浏览器显示的页面以外的部分。 ⏱ 2020-12-01 11:19:04

📌 BOM只处理浏览器窗口和框架 ⏱ 2020-12-01 11:20:40

📌 ❏ 对cookies的支持; ⏱ 2020-12-01 11:20:49

1.4 小结

📌 五个主要浏览器(IE、Firefox、Chrome、Safari和Opera) ⏱ 2020-12-01 11:41:43

2.1

📌 HTML 4.01为<script>定义了下列6个属性。 ⏱ 2020-12-01 11:42:39

📌 MIME类型 ⏱ 2020-12-01 11:48:22

📌 使用

📌 。与解析嵌入式JavaScript代码一样,在解析外部JavaScript文件(包括下载该文件)时,页面的处理也会暂时停止。 ⏱ 2020-12-01 14:02:49

📌 可是,在文档的元素中包含所有JavaScript文件,意味着必须等到全部JavaScript代码都被下载、解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到标签时才开始呈现内容)。 ⏱ 2020-12-01 14:04:46

📌 编写XHTML代码的规则要比编写HTML严格得多,而且直接影响能否在嵌入JavaScript代码时使用

2.5 小结

📌 在包含外部JavaScript文件时,必须将src属性设置为指向相应文件的URL。而这个文件既可以是与包含它的页面位于同一个服务器上的文件,也可以是其他任何域中的文件。 ⏱ 2020-12-01 14:12:51

3.2 关键字和保留字

📌 ECMA-262描述了一组具有特定用途的关键字,这些关键字可用于表示控制语句的开始或结束,或者用于执行特定操作等。 ⏱ 2020-09-17 01:15:09

3.3 变量

📌 ECMAScript的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据 ⏱ 2020-09-17 01:19:42

📌 这行代码定义了一个名为message的变量,该变量可以用来保存任何值(像这样未经过初始化的变量,会保存一个特殊的值——undefined, ⏱ 2020-09-17 01:18:50

📌 即用var操作符定义的变量将成为定义该变量的作用域中的局部变量。 ⏱ 2020-12-01 14:18:03

📌 而在此之后,这个变量又会立即被销毁 ⏱ 2020-12-01 14:18:14

3.4 数据类型

📌 Object本质上是由一组无序的名值对组成的。 ⏱ 2020-12-01 14:22:26

📌 typeof是一个操作符 ⏱ 2020-12-01 14:23:56

📌 对于尚未声明过的变量,只能执行一项操作,即使用typeof操作符检测其数据类型 ⏱ 2020-12-01 14:24:54

📌 如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值 ⏱ 2020-12-01 14:26:06

📌 undefined值是派生自null值的 ⏱ 2020-09-21 16:48:38

📌 这个操作符出于比较的目的会转换其操作数(本章后面将详细介绍相关内容)。 ⏱ 2020-09-21 16:48:53

📌 只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分null和undefined。 ⏱ 2020-12-01 14:27:09

📌 这两个值与数字值不是一回事,因此true不一定等于1,而false也不一定等于0。 ⏱ 2020-12-01 14:26:58

📌 虽然Boolean类型的字面值只有两个,但ECMAScript中所有类型的值都有与这两个Boolean值等价的值。要将一个值转换为其对应的Boolean值,可以调用转型函数Boolean(),如下例所示: ⏱ 2020-12-01 14:28:44

📌 因为字符串message被自动转换成了对应的Boolean值(true)。由于存在这种自动执行的Boolean转换,因此确切地知道在流控制语句中使用的是什么变量至关重要。错误地使用一个对象而不是一个Boolean值,就有可能彻底改变应用程序的流程。 ⏱ 2020-12-01 14:30:41

📌 这种类型使用IEEE754格式来表示整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。 ⏱ 2020-12-01 14:30:51

📌 除了以十进制表示外,整数还可以通过八进制(以8为基数)或十六进制(以16为基数)的字面值来表示。 ⏱ 2020-12-01 14:33:38

📌 八进制字面量在严格模式下是无效的,会导致支持该模式的JavaScript引擎抛出错误。 ⏱ 2020-12-01 14:33:47

📌 在默认情况下,ECMASctipt会将那些小数点后面带有6个零以上的浮点数值转换为以e表示法表示的数值(例如,0.0000003会被转换成3e-7)。 ⏱ 2020-12-01 14:37:45

📌 永远不要测试某个特定的浮点数值。 ⏱ 2020-12-01 14:38:24

📌 因为Infinity不是能够参与计算的数值 ⏱ 2020-12-01 14:39:39

📌 要想确定一个数值是不是有穷的(换句话说,是不是位于最小和最大的数值之间),可以使用isFinite()函数。 ⏱ 2020-12-01 14:39:49

📌 首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身。 ⏱ 2020-12-01 14:41:52

📌 因此为了避免错误的解析,我们建议无论在什么情况下都明确指定基数。 ⏱ 2020-12-01 14:49:19

📌 parseFloat()与parseInt()的第二个区别在于它始终都会忽略前导的零。 ⏱ 2020-12-01 17:39:20

📌 首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量, ⏱ 2020-12-03 16:44:16

📌 。实现这个操作的过程如下:首先创建一个能容纳10个字符的新字符串,然后在这个字符串中填充”Java”和”Script”,最后一步是销毁原来的字符串”Java”和字符串”Script”,因为这两个字符串已经没用了。 ⏱ 2020-12-03 16:44:27

4.1 基本类型和引用类型的值

📌 ECMAScript中所有函数的参数都是按值传递的 ⏱ 2020-12-03 17:22:07

📌 根据规定,所有引用类型的值都是Object的实例。因此,在检测一个引用类型值和Object构造函数时,instanceof操作符始终会返回true。 ⏱ 2020-10-12 22:16:17

4.2 执行环境及作用域

📌 全局执行环境是最外围的一个执行环境。根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样。 ⏱ 2020-12-05 10:58:49

📌 每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。 ⏱ 2020-09-21 18:56:43

📌 当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。 ⏱ 2020-09-21 18:56:49

📌 它自己的变量对象(其中定义着arguments对象)和全局环境的变量对象。 ⏱ 2020-10-12 22:46:18

📌 在swapColors()内部则可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境。 ⏱ 2020-10-12 23:03:11

📌 虽然执行环境的类型总共只有两种——全局和局部(函数),但还是有其他办法来延长作用域链 ⏱ 2020-10-12 23:03:51

📌 with语句接收的是location对象,因此其变量对象中就包含了location对象的所有属性和方法,而这个变量对象被添加到了作用域链的前端。 ⏱ 2020-10-12 23:04:02

📌 使用var声明的变量会自动被添加到最接近的环境中 ⏱ 2020-10-12 23:04:18

📌 函数内部,最接近的环境就是函数的局部环境;在with语句中,最接近的环境是函数环境。 ⏱ 2020-10-12 23:04:24

4.3 垃圾收集

📌 所需内存的分配以及无用内存的回收完全实现了自动管理。 ⏱ 2020-10-13 10:00:37

📌 垃圾收集器必须跟踪哪个变量有用哪个变量没用,对于不再有用的变量打上标记,以备将来收回其占用的内存。 ⏱ 2020-10-13 10:00:43

📌 JavaScript中最常用的垃圾收集方式是标记清除(mark-and-sweep) ⏱ 2020-12-03 17:42:02

📌 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记 ⏱ 2020-12-03 17:43:19

📌 另一种不太常见的垃圾收集策略叫做引用计数(reference counting)。 ⏱ 2020-10-13 10:01:00

📌 当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。 ⏱ 2020-12-03 17:44:20

📌 当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。 ⏱ 2020-12-03 17:44:26

📌 这两个对象的引用次数都是2。在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是个问题。但在采用引用计数策略的实现中,当函数执行完毕后,objectA和objectB还将继续存在,因为它们的引用次数永远不会是0。 ⏱ 2020-12-03 17:48:42

📌 即使IE的JavaScript引擎是使用标记清除策略来实现的,但JavaScript访问的COM对象依然是基于引用计数策略的。换句话说,只要在IE中涉及COM对象,就会存在循环引用的问题。 ⏱ 2020-12-03 17:49:10

📌 最好是在不使用它们的时候手工断开原生JavaScript对象与DOM元素之间的连接。例如,可以使用下面的代码消除前面例子创建的循环引用: ⏱ 2020-12-03 17:50:37

📌 触发垃圾收集的变量分配、字面量和(或)数组元素的临界值被调整为动态修正 ⏱ 2020-12-03 17:52:20

📌 JavaScript在进行内存管理及垃圾收集时面临的问题还是有点与众不同。其中最主要的一个问题,就是分配给Web浏览器的可用内存数量通常要比分配给桌面应用程序的少 ⏱ 2020-12-03 17:54:17

📌 确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用——这个做法叫做解除引用(dereferencing) ⏱ 2020-12-03 17:54:34

📌 解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。 ⏱ 2020-12-03 17:55:01

4.4 小结

📌 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中; ⏱ 2020-12-03 23:43:27

📌 引用类型的值是对象,保存在堆内存中; ⏱ 2020-12-03 23:43:31

📌 ❏ 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分; ⏱ 2020-12-03 23:44:56

📌 “标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。 ⏱ 2020-12-03 23:45:21

📌 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。 ⏱ 2020-12-03 23:45:35

第5章 引用类型

📌 引用类型是一种数据结构 ⏱ 2020-12-04 09:48:08

📌 尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构 ⏱ 2020-12-04 09:48:14

📌 对象是某个特定引用类型的实例 ⏱ 2020-12-05 11:17:37

5.2 Array类型

📌 sort()方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面 ⏱ 2020-12-05 11:37:38

📌 即使数组中的每一项都是数值,sort()方法比较的也是字符串, ⏱ 2020-12-05 11:37:46

📌 因此sort()方法可以接收一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面。 ⏱ 2020-12-05 11:38:00

📌 如果第一个参数应该位于第二个之前则返回一个负数 ⏱ 2020-12-05 11:38:04

📌 concat()方法可以基于当前数组中的所有项创建一个新数组 ⏱ 2020-12-05 11:46:18

📌 下一个方法是slice(),它能够基于当前数组中的一或多个项创建一个新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置 ⏱ 2020-12-05 11:48:28

📌 splice() ⏱ 2020-12-05 11:49:48

📌 splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组) ⏱ 2020-12-05 11:51:06

5.3 Date类型

📌 如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse() ⏱ 2020-12-05 14:00:12

5.5 Function类型

📌 但最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。 ⏱ 2020-12-05 14:15:34

📌 将函数名想象为指针,也有助于理解为什么ECMAScript中没有函数重载的概念 ⏱ 2020-12-05 14:16:17

📌 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。 ⏱ 2020-12-05 14:16:49

📌 。因为在代码开始执行之前,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中。 ⏱ 2020-12-05 14:16:57

📌 除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的 ⏱ 2020-12-05 14:18:54

📌 不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回 ⏱ 2020-12-05 14:19:12

📌 执行第一个参数后的结果 ⏱ 2020-12-05 14:20:16

📌 要解决这个问题,可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数 ⏱ 2020-12-05 14:31:33

📌 在函数内部,有两个特殊的对象:arguments和this。 ⏱ 2020-12-05 14:35:53

📌 虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。 ⏱ 2020-12-05 14:36:42

📌 但问题是这个函数的执行与函数名factorial紧紧耦合在了一起。为了消除这种紧密耦合的现象,可以像下面这样使用arguments.callee。 ⏱ 2020-12-05 14:36:54

📌 无论引用函数时使用的是什么名字,都可以保证正常完成递归调用 ⏱ 2020-12-05 14:37:12

📌 即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor()指向的仍然是同一个函数。 ⏱ 2020-12-05 14:57:07

📌 这个属性中保存着调用当前函数的函数的引用, ⏱ 2020-12-05 14:57:39

📌 因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。 ⏱ 2020-12-05 15:05:42

📌 length属性表示函数希望接收的命名参数的个数, ⏱ 2020-12-05 15:08:29

📌 对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。 ⏱ 2020-12-05 15:09:30

📌 诸如toString()和valueOf()等方法实际上都保存在prototype名下 ⏱ 2020-12-05 15:15:29

📌 每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值 ⏱ 2020-12-05 15:15:52

📌 apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组 ⏱ 2020-12-05 15:16:05

📌 ECMAScript 5还定义了一个方法:bind()。这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。 ⏱ 2020-12-05 15:17:58

5.6 基本包装类型

📌 ECMAScript还提供了3个特殊的引用类型:Boolean、Number和String。

  • 💭 这里的类型和基础数据类型不一样 - ⏱ 2020-12-05 15:19:22

📌 实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。 ⏱ 2020-12-05 15:43:00

📌 基本的字符串值就变得跟对象一样了。 ⏱ 2020-12-05 15:30:44

📌 引用类型与基本包装类型的主要区别就是对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁 ⏱ 2020-12-05 15:33:16

📌 问题的原因就是第二行创建的String对象在执行第三行代码时已经被销毁了。第三行代码又创建自己的String对象,而该对象没有color属性。 ⏱ 2020-12-05 15:36:14

📌 可以显式地调用Boolean、Number和String来创建基本包装类型的对象。不过,应该在绝对必要的情况下再这样做,因为这种做法很容易让人分不清自己是在处理基本类型还是引用类型的值。 ⏱ 2020-12-05 15:36:24

📌 使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的 ⏱ 2020-12-05 15:37:22

📌 布尔表达式中的所有对象都会被转换为true,因此falseObject对象在布尔表达式中代表的是true。结果,true && true当然就等于true了。 ⏱ 2020-12-05 15:37:51

📌 使得toFixed()方法很适合处理货币值 ⏱ 2020-12-05 15:41:25

📌 另外可用于格式化数值的方法是toExponential(),该方法返回以指数表示法(也称e表示法)表示的数值的字符串形式 ⏱ 2020-12-05 15:41:21

📌 虽然concat()是专门用来拼接字符串的方法,但实践中使用更多的还是加号操作符(+)。而且,使用加号操作符在大多数情况下都比使用concat()方法要简便易行( ⏱ 2020-12-05 15:51:15

5.7 单体内置对象

📌 由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。”意思就是说,开发人员不必显式地实例化内置对象,因为它们已经实例化了。 ⏱ 2020-12-05 15:58:42

📌 ECMA-262还定义了两个单体内置对象:Global和Math。 ⏱ 2020-12-05 15:58:46

📌 。换句话说,不属于任何其他对象的属性和方法,最终都是它的属性和方法。 ⏱ 2020-12-05 16:01:09

📌 UniformResource Identifiers ⏱ 2020-12-05 16:02:20

第6章 面向对象的程序设计

📌 ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。” ⏱ 2020-12-17 09:41:09

6.1 理解对象

📌 ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征 ⏱ 2020-12-17 09:43:44

📌 要修改属性默认的特性,必须使用ECMAScript 5的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。 ⏱ 2020-12-17 09:50:29

📌 这个例子创建了一个名为name的属性,它的值”Nicholas”是只读的。这个属性的值是不可修改的,如果尝试为它指定新值,则在非严格模式下,赋值操作将被忽略;在严格模式下,赋值操作将会导致抛出错误。 ⏱ 2020-12-17 09:50:41

📌 访问器属性有如下4个特性。 ⏱ 2020-12-17 11:16:00

📌 _year前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。 ⏱ 2020-12-05 17:56:37

📌 在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法:defineGetter()和__defineSetter__()。 ⏱ 2020-12-05 17:57:39

📌 两个数据属性(_year和edition)和一个访问器属性(year)。 ⏱ 2020-12-17 11:26:28

📌 如果是访问器属性,这个对象的属性有configurable、enumerable、get和set;如果是数据属性,这个对象的属性有configurable、enumerable、writable和value。 ⏱ 2020-12-17 11:25:54

6.2 创建对象

📌 但却没有解决对象识别的问题(即怎样知道一个对象的类型)。 ⏱ 2020-12-05 18:06:15

📌 直接将属性和方法赋给了this对象; ⏱ 2020-12-05 18:19:00

📌 没有return语句。 ⏱ 2020-12-05 18:19:03

📌 将构造函数的作用域赋给新对象(因此this就指向了这个新对象); ⏱ 2020-12-05 18:06:40

📌 创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正是构造函数模式胜过工厂模式的地方 ⏱ 2020-12-05 18:07:31

📌 就是每个方法都要在每个实例上重新创建一遍。 ⏱ 2020-12-05 18:21:04

📌 创建两个完成同样任务的Function实例的确没有必要;况且有this对象在,根本不用在执行代码前就把函数绑定到特定对象上面 ⏱ 2020-12-17 11:54:52

📌 也仍然可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法 ⏱ 2020-12-05 18:23:24

📌 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象 ⏱ 2020-12-17 12:02:10

📌 当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫Prototype。 ⏱ 2020-12-17 14:08:31

📌 Person.prototype指向了原型对象,而Person.prototype.constructor又指回了Person ⏱ 2020-12-07 09:56:44

📌 虽然在所有实现中都无法访问到Prototype,但可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。 ⏱ 2020-12-17 14:08:45

📌 Object.getPrototypeOf(),在所有支持的实现中,这个方法返回Prototype的值 ⏱ 2020-12-07 09:58:11

📌 每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。 ⏱ 2020-12-07 10:11:57

📌 虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。 ⏱ 2020-12-07 10:14:18

📌 使用hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。 ⏱ 2020-12-17 14:11:17

📌 调用person1.hasOwnProperty( “name”)时,只有当person1重写name属性后才会返回true, ⏱ 2020-12-17 14:13:19

📌 in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。 ⏱ 2020-12-17 14:13:34

📌 。同时使用hasOwnProperty()方法和in操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中, ⏱ 2020-12-17 14:13:55

📌 首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值 ⏱ 2020-12-07 10:20:48

📌 原型模式的最大问题是由其共享的本性所导致的。 ⏱ 2020-12-07 10:20:52

📌 对于包含引用类型值的属性来说,问题就比较突出了 ⏱ 2020-12-07 10:21:04

📌 由于friends数组存在于Person.prototype而非person1中,所以刚刚提到的修改也会通过person2.friends(与person1.friends指向同一个数组)反映出来。 ⏱ 2020-12-07 10:22:25

📌 构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。 ⏱ 2020-12-07 10:29:38

📌 这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。 ⏱ 2020-12-07 10:29:28

6.3 继承

📌 许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,由于函数没有签名,在ECMAScript中无法实现接口继承。ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。 ⏱ 2020-12-07 10:42:48

📌 其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法 ⏱ 2020-12-07 10:43:17

📌 代码中加粗的那一行代码“借调”了超类型的构造函数。通过使用call()方法(或apply()方法也可以),我们实际上是在(未来将要)新创建的SubType实例的环境下调用了SuperType构造函数 ⏱ 2020-12-17 14:55:52

📌 这样一来,就可以让两个不同的SubType实例既分别拥有自己属性——包括colors属性,又可以使用相同的方法了。 ⏱ 2020-12-17 15:03:14

📌 开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。 ⏱ 2020-12-17 14:58:29

第7章 函数表达式

📌 第5章曾介绍过,定义函数的方式有两种:一种是函数声明,另一种就是函数表达式 ⏱ 2020-12-08 11:40:29

📌 。Firefox、Safari、Chrome和Opera都给函数定义了一个非标准的name属性,通过这个属性可以访问到给函数指定的名字 ⏱ 2020-12-08 11:40:17

📌 关于函数声明,它的一个重要特征就是函数声明提升(function declarationhoisting),意思是在执行代码之前会先读取函数声明。 ⏱ 2020-12-17 15:06:54

📌 即创建一个函数并将它赋值给变量functionName。这种情况下创建的函数叫做匿名函数(anonymous function),因为function关键字后面没有标识符。(匿名函数有时候也叫拉姆达函数。)匿名函数的name属性是空字符串。 ⏱ 2020-12-08 11:41:37

7.1 递归

📌 但下面的代码却可能导致它出错。 ⏱ 2020-12-17 15:08:18

📌 argu-ments.callee可以解决这个问题。 ⏱ 2020-12-17 15:08:39

📌 arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用, ⏱ 2020-12-17 15:08:41

📌 以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。 ⏱ 2020-12-17 15:11:19

7.2 闭包

📌 闭包是指有权访问另一个函数作用域中的变量的函数 ⏱ 2020-09-16 17:38:16

📌 创建闭包的常见方式,就是在一个函数内部创建另一个函数, ⏱ 2020-09-16 18:38:25

📌 当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链 ⏱ 2020-12-08 11:58:44

📌 一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。 ⏱ 2020-12-18 10:17:37

📌 因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中; ⏱ 2020-12-18 10:26:05

📌 由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包。 ⏱ 2020-12-18 10:33:22

📌 作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。 ⏱ 2020-12-18 10:42:46

📌 但实际上,每个函数都返回10。因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。 ⏱ 2020-12-18 10:42:29

📌 在闭包中使用this对象也可能会导致一些问题。我们知道,this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。 ⏱ 2020-12-19 10:29:22

📌 因此永远不可能直接访问外部函数中的这两个变量( ⏱ 2020-12-21 11:13:40

📌 第三行代码先执行了一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值不能得到维持,结果就返回了”The Window”。 ⏱ 2020-12-21 11:18:19

7.4 私有变量

📌 果在这个函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量。而利用这一点,就可以创建用于访问私有变量的公有方法。 ⏱ 2020-12-21 11:29:36

📌 模块模式 ⏱ 2020-12-21 11:37:40

📌 而道格拉斯所说的模块模式(module pattern)则是为单例创建私有变量和特权方法。所谓单例(singleton),指的就是只有一个实例的对象。 ⏱ 2020-12-21 11:49:54

📌 模块模式通过为单例添加私有变量和特权方法能够使其得到增强 ⏱ 2020-12-21 11:42:38

8.1 Window对象

📌 超时调用需要使用window对象的setTimeout()方法,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒) ⏱ 2020-12-26 00:04:49

8.2 Location对象

📌 location是最有用的BOM对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能 ⏱ 2020-12-26 00:18:38

📌 window.location和document.location引用的是同一个对象 ⏱ 2020-12-26 00:18:44

📌 查询字符串参数 ⏱ 2020-12-26 00:23:09

📌 当通过上述任何一种方式修改URL之后,浏览器的历史记录中就会生成一条新记录,因此用户通过单击“后退”按钮都会导航到前一个页面。 ⏱ 2020-12-26 00:26:27

📌 “后退”按钮将处于禁用状态,如果不重新输入完整的URL,则无法返回示例页面。 ⏱ 2020-12-31 18:07:06

8.3 Navigator对象

📌 最早由Netscape Navigator 2.0引入的navigator对象,现在已经成为识别客户端浏览器的事实标准 ⏱ 2020-12-31 18:10:31

8.4 Screen对象

📌 许多浏览器都会禁用调整浏览器窗口大小的能力,因此上面这行代码不一定在所有环境下都有效。 ⏱ 2021-01-04 09:58:24

9.1 能力检测

📌 能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。 ⏱ 2021-01-04 10:07:32

📌 更好的方式是检测sort是不是一个函数。 ⏱ 2021-01-04 10:09:32

9.3 用户代理检测

📌 第三种,也是争议最大的一种客户端检测技术叫做用户代理检测。用户代理检测通过检测用户代理字符串来确定实际使用的浏览器 ⏱ 2021-01-04 10:22:27

📌 一般来说,确定浏览器是否基于WebKit要比确定它是不是Safari更有价值,就像针对Gecko一样。 ⏱ 2021-01-04 10:34:47

📌 移动操作系统iOS和Android默认的浏览器都基于WebKit,而且都像它们的桌面版一样,共享相同的基本用户代理字符串格式。 ⏱ 2021-01-04 10:35:04

📌 而x11表示Unix ⏱ 2021-01-04 10:45:51

📌 用户代理检测是客户端检测的最后一个选择。只要可能,都应该优先采用能力检测和怪癖检测。 ⏱ 2021-01-04 10:47:43

第10章 DOM

📌 DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。 ⏱ 2021-01-04 10:51:52

10.1 节点层次

📌 文档节点是每个文档的根节点。 ⏱ 2021-01-04 10:54:29

📌 要注意length属性表示的是访问NodeList的那一刻,其中包含的节点数量 ⏱ 2021-01-04 11:26:05

📌 hasChildNodes() ⏱ 2021-01-04 11:50:03

📌 ownerDocument ⏱ 2021-01-04 11:51:25

📌 如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。即使可以将DOM树看成是由一系列指针连接起来的,但任何DOM节点也不能同时出现在文档中的多个位置上。 ⏱ 2021-01-04 11:55:42

📌 这个方法接受两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。如果参照节点是null,则insertBefore()与appendChild()执行相同的操作, ⏱ 2021-01-04 14:12:10

📌 第一个就是cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本。cloneNode()方法接受一个布尔值参数,表示是否执行深复制。 ⏱ 2021-01-04 14:33:13

📌 我们都用不着在document对象上调用appendChild()、removeChild()和replaceChild()方法,因为文档类型(如果存在的话)是只读的,而且它只能有一个元素子节点(该节点通常早就已经存在了)。 ⏱ 2021-01-04 17:41:54

📌 Document类型为此提供了两个方法:getElementById()和getElementsByTagName()。 ⏱ 2021-01-04 17:44:48

📌 第一个方法,getElementById(),接收一个参数:要取得的元素的ID。如果找到相应的元素则返回该元素,如果不存在带有相应ID的元素,则返回null ⏱ 2021-01-04 17:44:55

📌 getElementsByName()方法返回一个NodeList。 ⏱ 2021-01-04 17:49:05

📌 document.createTextNode() ⏱ 2021-01-04 17:56:35

10.2 DOM操作技术

📌 必须将元素添加到而不是元素, ⏱ 2021-01-04 18:07:42

📌 加载外部样式文件的过程是异步的,也就是加载样式与执行JavaScript代码的过程没有固定的次序 ⏱ 2021-01-04 18:13:04

📌 理解NodeList及其“近亲”NamedNodeMap和HTMLCollection,是从整体上透彻理解DOM的关键所在。 ⏱ 2021-01-04 18:19:15

📌 从本质上说,所有NodeList对象都是在访问DOM文档时实时运行的查询 ⏱ 2021-01-04 18:19:23

10.3 小结

📌 理解DOM的关键,就是理解DOM对性能的影响。DOM操作往往是JavaScript程序中开销最大的部分,而因访问NodeList导致的问题为最多。NodeList对象都是“动态的”,这就意味着每次访问NodeList对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM操作。 ⏱ 2021-01-04 18:18:54

11.1 选择符API

📌 querySelector()方法 ⏱ 2021-01-04 18:20:45

📌 querySelectorAll()方法接收的参数与querySelector()方法一样,都是一个CSS选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个NodeList的实例。 ⏱ 2021-01-04 18:21:22

📌 Selectors API Level 2规范为Element类型新增了一个方法matchesSelector()。这个方法接收一个参数,即CSS选择符,如果调用元素与该选择符匹配,返回true;否则,返回false ⏱ 2021-01-04 18:22:29

11.2 元素遍历

📌 IE9及之前版本不会返回文本节点,而其他所有浏览器都会返回文本节点。这样,就导致了在使用childNodes和firstChild等属性时的行为不一致。为了弥补这一差异,而同时又保持DOM规范不变,Element Traversal规范(www.w3.org/TR/ElementTraversal/)新定义了一组属性。 ⏱ 2021-01-04 18:26:23

11.3 HTML5

📌 document对象引入了readyState属性 ⏱ 2021-01-04 18:31:16

📌 ❏ loading,正在加载文档;❏ complete,已经加载完文档。 ⏱ 2021-01-04 18:31:20

📌 在标准模式下,document.compatMode的值等于”CSS1Compat”,而在混杂模式下,document.compatMode的值等于”BackCompat”。 ⏱ 2021-01-04 18:32:20

📌 ,HTML5新增了document.head属性,引用文档的元素。要引用文档的元素,可以结合使用这个属性和另一种后备方法。 ⏱ 2021-01-04 18:32:38

📌 比如,在大多数浏览器中,通过innerHTML插入

📌 。第三行代码使用的是一个隐藏的<input>域,也能达到相同的效果。不过,由于隐藏的<input>域不影响页面布局,因此这种方式在大多数情况下都是首选。 ⏱ 2021-01-05 09:47:50

📌 使用本节介绍的方法替换子节点可能会导致浏览器的内存占用问题, ⏱ 2021-01-04 18:39:32

📌 因此,在使用innerHTML、outerHTML属性和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性 ⏱ 2021-01-04 18:39:41

📌 最好的做法是单独构建字符串,然后再一次性地将结果字符串赋值给innerHTML,像下面这样: ⏱ 2021-01-04 18:40:17

11.4 专有扩展

📌 children属性与childNodes没有什么区别,即在元素只包含元素子节点时,这两个属性的值相同。 ⏱ 2021-01-05 10:10:16

📌 经常需要知道某个节点是不是另一个节点的后代。IE为此率先引入了contains()方法, ⏱ 2021-01-05 10:13:59

📌 通过innertText属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。 ⏱ 2021-01-05 10:20:14

📌 除了作用范围扩大到了包含调用它的节点之外,outerText与innerText基本上没有多大区别。 ⏱ 2021-01-05 10:24:59

第12章 DOM2和DOM3

📌 DOM1级主要定义的是HTML和XML文档的底层结构。DOM2和DOM3级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性 ⏱ 2021-01-05 20:46:29

12.1 DOM变化

📌 DOM2级和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力 ⏱ 2021-01-05 21:37:05

📌 在只基于一种语言编写XML文档的情况下,命名空间实际上也没有什么用。不过,在混合使用两种语言的情况下,命名空间的用处就非常大了。来看一看下面这个混合了XHTML和SVG语言的文档: ⏱ 2021-01-05 21:40:20

12.2 样式

📌 getPropertyCSSValue()使用得比getPropertyValue()少得多 ⏱ 2021-01-05 21:44:14

📌 在默认情况下,有的浏览器将visibility属性设置为”visible”,而有的浏览器则将其设置为”inherit”。换句话说,不能指望某个CSS属性的默认值在不同浏览器中是相同的 ⏱ 2021-01-05 21:46:47

📌 offsetHeight:元素在垂直方向上占用的空间大小,以像素计。 ⏱ 2021-01-05 23:53:14

📌 offsetWidth:元素在水平方向上占用的空间大小 ⏱ 2021-01-05 23:53:19

📌 元素的左外边框至包含元素的左内边框之间的像素距离。 ⏱ 2021-01-06 11:42:11

📌 。对于简单的CSS布局的页面,这两函数可以得到非常精确的结果。对于使用表格和内嵌框架布局的页面,由于不同浏览器实现这些元素的方式不同,因此得到的值就不太精确了。 ⏱ 2021-01-06 00:06:45

📌 因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性的值,可以将它们保存在局部变量中,以提高性能。 ⏱ 2021-01-06 00:06:53

12.3 遍历

📌 创建TreeWalker对象要使用document.createTreeWalker()方法, ⏱ 2021-01-06 18:15:22

第13章 事件

📌 JavaScript与HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。 ⏱ 2021-01-07 09:40:17

📌 使用事件有时相对简单,有时则非常复杂,难易程度会因你的需求而不同。不过,有关事件的一些核心概念是一定要理解的。 ⏱ 2021-01-07 09:44:11

13.1 事件流

📌 即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。 ⏱ 2021-01-07 09:49:48

📌 也就是说,click事件首先在

元素上发生,而这个元素就是我们单击的元素。然后,click事件沿DOM树向上传播,在每一级节点上都会发生 ⏱ 2021-01-07 09:49:39 ^26211817-82-1641-1719

📌 在事件捕获过程中,document对象首先接收到click事件,然后事件沿DOM树依次向下,一直传播到事件的实际目标,即

元素。 ⏱ 2021-01-07 09:51:22 ^26211817-82-2667-2741

📌 “DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。 ⏱ 2021-01-07 09:51:35

📌 下一个阶段是“处于目标”阶段,于是事件在

上发生,并在事件处理(后面将会讨论这个概念)中被看成冒泡阶段的一部分 ⏱ 2021-01-07 10:00:16 ^26211817-82-3875-3940

13.2 事件处理程序

📌 而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以”on”开头,因此click事件的事件处理程序就是onclick, load事件的事件处理程序就是onload。 ⏱ 2021-01-07 10:09:07

📌 某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。 ⏱ 2021-01-07 10:21:50

📌 由于这个值是JavaScript,因此不能在其中使用未经转义的HTML语法字符,例如和号(&)、双引号("")、小于号(<)或大于号(>) ⏱ 2021-01-07 10:22:12

📌 首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个局部变量event,也就是事件对象 ⏱ 2021-01-07 10:31:21

📌 通过event变量,可以直接访问事件对象,你不用自己定义它,也不用从函数的参数列表中读取 ⏱ 2021-01-07 10:53:45

📌 this值等于事件的目标元素 ⏱ 2021-01-07 11:00:48

📌 另一个有意思的地方是它扩展作用域的方式。在这个函数内部,可以像访问局部变量一样访问document及该元素本身的成员 ⏱ 2021-01-07 11:01:00

📌 无非就是想让事件处理程序无需引用表单元素就能访问其他表单字段 ⏱ 2021-01-07 10:58:06

📌 如果用户在页面解析showMessage()函数之前就单击了按钮,就会引发错误。为此,很多HTML事件处理程序都会被封装在一个try-catch块中,以便错误不会浮出水面 ⏱ 2021-01-07 11:01:57

📌 通过HTML指定事件处理程序的最后一个缺点是HTML与JavaScript代码紧密耦合。如果要更换事件处理程序,就要改动两个地方:HTML代码和JavaScript代码。 ⏱ 2021-01-07 11:03:11

📌 每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写, ⏱ 2021-01-07 11:03:52

📌 在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。 ⏱ 2021-01-07 11:07:21

📌 使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的this引用当前元素。来看一个例子。

  • 💭 DOM0 on - ⏱ 2021-01-07 11:07:35

📌 以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。 ⏱ 2021-01-07 11:12:06

📌 也可以删除通过DOM0级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为null即可: ⏱ 2021-01-07 11:12:14

📌 “DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。 ⏱ 2021-01-07 11:15:38

📌 并且它们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。 ⏱ 2021-01-07 11:18:12

📌 上面的代码为一个按钮添加了onclick事件处理程序,而且该事件会在冒泡阶段被触发(因为最后一个参数是false ⏱ 2021-01-07 11:34:15

📌 移除时传入的参数与添加处理程序时使用的参数相同。

  • 💭 useCapture也需要相同 - ⏱ 2021-01-07 11:34:39

📌 但实际上,第二个参数与传入addEventListener()中的那一个是完全不同的函数 ⏱ 2021-01-07 11:35:18

13.3 事件对象

📌 在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。 ⏱ 2021-01-07 11:59:18

📌 兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0级或DOM2级),都会传入event对象 ⏱ 2021-01-07 11:59:31

📌 在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标 ⏱ 2021-01-09 11:40:13

📌 要阻止特定事件的默认行为,可以使用preventDefault()方法。例如,链接的默认行为就是在被单击时会导航到其href特性指定的URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick事件处理程序可以取消它 ⏱ 2021-01-09 11:46:21

📌 如果是在捕获阶段调用的事件处理程序,那么eventPhase等于1;如果事件处理程序处于目标对象上,则event-Phase等于2;如果是在冒泡阶段调用的事件处理程序,eventPhase等于3。 ⏱ 2021-01-09 11:49:06

📌 只有在事件处理程序执行期间,event对象才会存在;一旦事件处理程序执行完成,event对象就会被销毁。 ⏱ 2021-01-09 14:07:50

13.4 事件类型

📌 与load事件对应的是unload事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生unload事件。 ⏱ 2021-01-13 11:34:15

📌 既然unload事件是在一切都被卸载之后才触发,那么在页面加载后存在的那些对象,此时就不一定存在了。此时,操作DOM节点或者元素的样式就会导致错误。 ⏱ 2021-01-13 11:36:24

13.5 内存和性能

📌 可是在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。 ⏱ 2021-01-16 19:13:36

📌 首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间 ⏱ 2021-01-16 19:13:42

📌 对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。 ⏱ 2021-01-16 19:25:34

📌 也就是说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。 ⏱ 2021-01-16 19:27:52

📌 ,可以利用事件委托技术解决这个问题。使用事件委托,只需在DOM树中尽量最高的层次上添加一个事件处理程序 ⏱ 2021-01-16 21:20:38

📌 故而可以通过检测id属性来决定采取适当的操作 ⏱ 2021-01-16 21:45:02

📌 ,因为只取得了一个DOM元素,只添加了一个事件处理程序。虽然对用户来说最终的结果相同,但这种技术需要占用的内存更少 ⏱ 2021-01-16 21:45:22

📌 只添加一个事件处理程序所需的DOM引用更少 ⏱ 2021-01-17 12:07:19

📌 最适合采用事件委托技术的事件包括click、mousedown、mouseup、keydown、keyup和keypress。虽然mouseover和mouseout事件也冒泡 ⏱ 2021-01-17 12:06:47

📌 为避免双击,单击这个按钮时就将按钮移除并替换成一条消息 ⏱ 2021-01-17 15:44:17

📌 如果你知道某个元素即将被移除,那么最好手工移除事件处理程序, ⏱ 2021-01-17 15:44:33

📌 最好的做法是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。 ⏱ 2021-01-17 15:46:06

📌 需要跟踪的事件处理程序越少,移除它们就越容易 ⏱ 2021-01-17 15:46:10

13.6 模拟事件

📌 也可以使用JavaScript在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样 ⏱ 2021-01-17 15:46:23

📌 在创建了event对象之后,还需要使用与事件有关的信息对其进行初始化。 ⏱ 2021-01-17 15:55:39

📌 模拟事件的最后一步就是触发事件。 ⏱ 2021-01-17 15:55:42

14.1 表单的基础知识

📌 浏览器会在将请求发送给服务器之前触发submit事件。这样,我们就有机会验证表单数据,并据以决定是否允许表单提交。阻止这个事件的默认行为就可以取消表单提交。 ⏱ 2021-01-17 23:37:33

📌 调用preventDefault()方法阻止了表单提交。一般来说,在表单数据无效而不能发送给服务器时,可以使用这一技术。 ⏱ 2021-01-17 23:42:20

📌 这种方式无需表单包含提交按钮,任何时候都可以正常提交表单。 ⏱ 2021-01-17 23:42:28

📌 因此要记得在调用此方法之前先验证表单数据。 ⏱ 2021-01-17 23:42:34

📌 。解决这一问题的办法有两个:在第一次提交表单后就禁用提交按钮,或者利用onsubmit事件处理程序取消后续的表单提交操作。 ⏱ 2021-01-17 23:42:49

📌 这个elements集合是一个有序列表,其中包含着表单中的所有字段,例如

📌 每个表单字段都有两个方法:focus()和blur() ⏱ 2021-01-18 00:13:33

15.1 基本用法

📌 要使用元素,必须先设置其width和height属性,指定可以绘图的区域大小。 ⏱ 2021-01-19 12:36:15 ^26211817-97-440-493

15.3 WebGL

📌 WebGL是针对Canvas的3D上下文 ⏱ 2021-01-19 17:28:11

📌 WebGL只能绘制三种形状:点、线和三角。其他所有形状都是由这三种基本形状合成之后,再绘制到三维空间中的 ⏱ 2021-01-19 17:37:53

16.2 原生拖放

📌 不过,你可以把任何元素变成有效的放置目标,方法是重写dragenter和dragover事件的默认行为。 ⏱ 2021-01-19 18:01:58

18.2 浏览器对XPath的支持

📌 selectSingleNode() ⏱ 2021-01-19 21:35:39

📌 selectNodes() ⏱ 2021-01-19 21:35:41

📌 为了求得最佳的浏览器兼容性,我们建议在JavaScript中使用XPath时,只考虑使用这两个方法。 ⏱ 2021-01-19 21:35:20

第20章 JSON

📌 JavaScript Object Notation ⏱ 2021-01-19 21:44:51

📌 最重要的是要理解它是一种数据格式 ⏱ 2021-01-19 21:44:49

20.1 语法

📌 JavaScript字符串与JSON字符串的最大区别在于,JSON字符串必须使用双引号(单引号会导致语法错误)。 ⏱ 2021-01-19 22:55:11

📌 JSON中的对象要求给属性加引号 ⏱ 2021-01-21 13:45:37

📌 对象的属性必须加双引号,这在JSON中是必需的。 ⏱ 2021-01-21 13:59:21

20.2 解析与序列化

📌 早期的JSON解析器基本上就是使用JavaScript的eval()函数。 ⏱ 2021-01-21 14:04:12

📌 使用eval()对JSON数据结构求值存在风险,因为可能会执行一些恶意代码。 ⏱ 2021-01-21 14:18:57

📌 JSON对象有两个方法:stringify()和parse()。 ⏱ 2021-01-21 14:04:19

📌 此外,值为undefined的任何属性也都会被跳过。结果中最终都是值为有效JSON数据类型的实例属性。 ⏱ 2021-01-21 14:32:15

📌 以给对象定义toJSON()方法,返回其自身的JSON数据格式。 ⏱ 2021-01-21 23:57:41

20.3 小结

📌 JSON是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量。 ⏱ 2021-01-22 13:18:58

第21章 Ajax与Comet

📌 这一技术能够向服务器请求额外的数据而无须卸载页面,会带来更好的用户体验 ⏱ 2021-01-22 13:21:05

📌 Ajax技术的核心是XMLHttpRequest对象(简称XHR),这是由微软首先引入的一个特性,其他浏览器提供商后来都提供了相同的实现 ⏱ 2021-01-22 13:23:32

21.1 XMLHttpRequest对象

📌 GET请求。 ⏱ 2021-01-22 14:49:19

📌 二是调用open()方法并不会真正发送请求,而只是启动一个请求以备发送。 ⏱ 2021-01-22 14:49:31

📌 statusText:HTTP状态的说明。 ⏱ 2021-01-22 15:14:47

📌 此外,状态代码为304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本;当然,也意味着响应是有效的。 ⏱ 2021-01-22 15:16:40

📌 只要readyState属性的值由一个值变成另一个值,都会触发一次readystatechange事件。 ⏱ 2021-01-22 15:28:00

📌 GET是最常见的请求类型,最常用于向服务器查询某些信息。 ⏱ 2021-01-22 16:07:37

📌 服务器对POST请求和提交Web表单的请求并不会一视同仁。 ⏱ 2021-01-22 16:27:31

📌 不过,我们可以使用XHR来模仿表单提交:首先将Content-Type头部信息设置为application/x-www-form-urlencoded, ⏱ 2021-01-22 17:32:23

📌 与GET请求相比,POST请求消耗的资源会更多一些。从性能角度来看,以发送相同的数据计,GET请求的速度最多可达到POST请求的两倍。 ⏱ 2021-01-22 17:33:19

21.2 XMLHttpRequest 2级

📌 而XMLHttpRequest 2级则进一步发展了XHR。 ⏱ 2021-01-22 17:14:57

📌 使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息。 ⏱ 2021-01-22 17:18:39

📌 意味着如果请求在1秒钟内还没有返回,就会自动终止。 ⏱ 2021-01-22 17:35:08

📌 但此时readyState可能已经改变为4了,这意味着会调用onreadystatechange事件处理程序。 ⏱ 2021-01-22 17:37:02

📌 ,用于重写XHR响应的MIME类型。 ⏱ 2021-01-22 17:37:37

21.3 进度事件

📌 有以下6个进度事件。 ⏱ 2021-01-23 14:17:55

📌 load:在接收到完整的响应数据时触发。 ⏱ 2021-01-23 14:16:52

📌 Firefox实现中引入了load事件,用以替代readystatechange事件。响应接收完毕后将触发load事件,因此也就没有必要去检查readyState属性了。 ⏱ 2021-01-23 14:17:04

📌 onload事件处理程序会接收到一个event对象,其target属性就指向XHR对象实例 ⏱ 2021-01-23 14:17:16

📌 lengthComputable、position和totalSize。其中,lengthComputable是一个表示进度信息是否可用的布尔值,position表示已经接收的字节数,totalSize表示根据Content-Length响应头部确定的预期字节数。有了这些信息,我们就可以为用户创建一个进度指示器了。 ⏱ 2021-01-23 14:26:51

21.4 跨源资源共享

📌 通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略 ⏱ 2020-12-17 17:58:52

📌 默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源。 ⏱ 2021-01-23 15:32:14

📌 CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通 ⏱ 2020-12-17 17:59:07

📌 CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。 ⏱ 2020-12-17 17:59:10

📌 如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中回发相同的源信息(如果是公共资源,可以回发”*”) ⏱ 2021-01-23 19:57:59

📌 默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。 ⏱ 2021-01-23 21:34:47

21.5 其他跨域技术

📌 图像Ping是与服务器进行简单、单向的跨域通信的一种方式。 ⏱ 2021-01-23 21:46:52

📌 图像Ping最常用于跟踪用户点击页面或动态广告曝光次数。图像Ping有两个主要的缺点,一是只能发送GET请求,二是无法访问服务器的响应文本。 ⏱ 2021-01-23 21:55:22

📌 这里指定的回调函数的名字叫handleResponse()。 ⏱ 2021-01-23 23:09:08

📌 JSONP是通过动态

📌 JSONP之所以在开发人员中极为流行,主要原因是它非常简单易用。与图像Ping相比,它的优点在于能够直接访问响应文本,支持在浏览器与服务器之间双向通信。 ⏱ 2021-01-23 23:12:02

📌 Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。Comet能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。 ⏱ 2021-01-24 13:24:14

📌 页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。 ⏱ 2021-01-24 13:26:14

📌 ,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。 ⏱ 2021-01-24 13:56:23

📌 短轮询是服务器立即发送响应, ⏱ 2021-01-24 13:26:22

📌 第二种流行的Comet实现是HTTP流。流不同于上述两种轮询,因为它在页面的整个生命周期内只使用一个HTTP连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。 ⏱ 2021-01-24 13:26:42

📌 通过侦听readystatechange事件及检测readyState的值是否为3, ⏱ 2021-01-24 13:26:51

📌 当readyState值变为3时,responseText属性中就会保存接收到的所有数据 ⏱ 2021-01-24 13:27:33

📌 只要readystatechange事件发生,而且readyState值为3,就对responseText进行分割以取得最新数据。 ⏱ 2021-01-24 14:02:04

📌 SSE(Server-SentEvents,服务器发送事件)是围绕只读Comet交互推出的API或者模式。 ⏱ 2021-01-24 14:10:29

📌 EventSource对象会保持与服务器的活动连接。如果连接断开,还会重新连接。这就意味着SSE适合长轮询和HTTP流 ⏱ 2021-01-24 14:32:53

📌 WebSockets的目标是在一个单独的持久连接上提供全双工、双向通信。 ⏱ 2021-01-24 14:13:00

📌 由于传递的数据包很小,因此Web Sockets非常适合移动应用。毕竟对移动应用而言,带宽和网络延迟都是关键问题 ⏱ 2021-01-24 14:13:45

📌 必须给WebSocket构造函数传入绝对URL。同源策略对WebSockets不适用,因此可以通过它打开到任何站点的连接。至于是否会与某个域中的页面通信,则完全取决于服务器。 ⏱ 2021-01-24 14:14:00

📌 当服务器向客户端发来消息时,WebSocket对象就会触发message事件。 ⏱ 2021-01-24 14:20:40

📌 event.data中返回的数据也是字符串 ⏱ 2021-01-24 14:21:57

📌 首先,你是否有自由度建立和维护Web Sockets服务器 ⏱ 2021-01-24 14:22:44

📌 第二个要考虑的问题是到底需不需要双向通信。 ⏱ 2021-01-24 14:22:26

21.6 安全

📌 对于未被授权系统有权访问某个资源的情况,我们称之为CSRF(Cross-Site Request Forgery,跨站点请求伪造)。未 ⏱ 2021-01-24 14:35:40

📌 CSRF ⏱ 2021-01-24 14:35:09

22.1 高级函数

📌 而且还必须与Array构造函数在同个全局作用域中。 ⏱ 2021-01-24 14:59:48

22.3 高级定时器

📌 DOM操作比起非DOM交互需要更多的内存和CPU时间。连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时候甚至会崩溃。 ⏱ 2021-01-24 15:37:32

📌 函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个 ⏱ 2021-01-24 15:37:48

📌 throttle()函数接受两个参数:要执行的函数以及在哪个作用域中执行 ⏱ 2021-01-24 15:38:35

📌 只要代码是周期性执行的,都应该使用节流,但是你不能控制请求执行的速率。这里展示的throttle()函数用了100ms作为间隔,你当然可以根据你的需要来修改它。 ⏱ 2021-01-24 15:37:19

23.1 离线检测

📌 HTML5还定义了两个事件:online和offline。当网络从离线变为在线或者从在线变为离线时,分别触发这两个事件 ⏱ 2021-01-24 15:46:00

23.3 数据存储

📌 该标准要求服务器对任意HTTP请求发送Set-CookieHTTP头作为响应的一部分,其中包含会话信息 ⏱ 2021-01-24 22:18:39

📌 也就是,何时应该停止向服务器发送这个cookie) ⏱ 2021-01-24 22:48:12

📌 document.cookie返回当前页面可用的(根据cookie的域、路径、失效时间和安全设置)所有cookie的字符串, ⏱ 2021-01-24 22:50:00

📌 sessionStorage对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。 ⏱ 2021-01-24 23:20:07

📌 要访问同一个localStorage对象,页面必须来自同一个域名(子域名无效),使用同一种协议,在同一个端口上。这相当于globalStorage[location.host]。 ⏱ 2021-01-24 23:36:08

📌 对Storage对象进行任何修改,都会在文档上触发storage事件。 ⏱ 2021-01-24 23:38:13

📌 Chrome和Safari对每个来源的限制是2.5MB。而iOS版Safari和Android版WebKit的限制也是2.5MB。 ⏱ 2021-01-24 23:47:48

24.1 可维护性

📌 直接将值与null比较是使用过度的,并且常常由于不充分的类型检查导致错误 ⏱ 2021-01-25 00:23:56

📌 values参数应该是一个数组,那么就要检查它是不是一个数组,而不是检查它是否非null。 ⏱ 2021-01-25 00:24:19

24.2 性能

📌 在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。 ⏱ 2021-01-25 00:24:44

📌 记住使用“后测试”循环时必须确保要处理的值至少有一个 ⏱ 2021-01-25 00:25:23

📌 当循环的次数是确定的,消除循环并使用多次函数调用往往更快。请看一下前面的例子。 ⏱ 2021-01-25 00:25:37

📌 因为自增操作符是后缀操作符,i的值只有在语句其他部分结束之后才会增加。 ⏱ 2021-01-25 00:26:20

📌 每一个更改,不管是插入单个字符,还是移除整个片段,都有一个性能惩罚,因为浏览器要重新计算无数尺寸以进行更新。 ⏱ 2021-01-25 00:27:12

📌 第二个方法是使用文档片段来构建DOM结构,接着将其添加到List元素中。 ⏱ 2021-01-25 00:27:45

📌 使用诸如createElement()和appendChild()之类的DOM方法,以及使用innerHTML。对于小的DOM更改而言,两种方法效率都差不多。然而,对于大的DOM更改,使用innerHTML要比使用标准DOM方法创建同样的DOM结构快得多。 ⏱ 2021-01-25 00:28:18

📌 当把innerHTML设置为某个值时,后台会创建一个HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于JavaScript的DOM调用。 ⏱ 2021-01-25 00:28:26

📌 使用innerHTML的关键在于(和其他DOM操作一样)最小化调用它的次数 ⏱ 2021-01-25 00:29:14

24.3 部署

📌 这个方法的问题在于它不是最优的,你写的代码不应该原封不动地放入浏览器中,理由如下所示。 ⏱ 2021-01-25 01:00:57

📌 记住将代码分离成多个文件只是为了提高可维护性,并非为了部署。 ⏱ 2021-01-25 01:01:14

📌 推荐Web应用中尽可能使用最少的JavaScript文件,是因为HTTP请求是Web中的主要性能瓶颈之一。记住通过

读书笔记

5.6 基本包装类型

划线评论

📌 ECMAScript还提供了3个特殊的引用类型:Boolean、Number和String。 ^8292450-7mmQ29ulE - 💭 这里的类型和基础数据类型不一样 - ⏱ 2020-12-05 15:32:16

13.2 事件处理程序

划线评论

📌 使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的this引用当前元素。来看一个例子。 ^8292450-7naKV7jFV - 💭 DOM0 on - ⏱ 2021-01-07 11:07:43

划线评论

📌 移除时传入的参数与添加处理程序时使用的参数相同。 ^8292450-7naMHSyxH - 💭 useCapture也需要相同 - ⏱ 2021-01-07 11:35:00

本书评论

书评 No.1

⏱ 2021-01-25 01:05:58