第十章 DOM
- 1001、每一段标记都可以通过树中的一个节点来表示:HTML 元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。总共有 12 种节点类型,这些类型都继承自一个基类型
- 1002、JavaScript 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法
- 1003、所有节点都有的最后一个属性是 ownerDocument ,该属性指向表示整个文档的文档节点。这种关系表示的是任何节点都属于它所在的文档,任何节点都不能同时存在于两个或更多个文档中。通过这个属性,我们可以不必在节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点
- 1004、如果需要把节点放在 childNodes 列表中某个特定的位置上,而不是放在末尾,那么可以使用insertBefore() 方法。这个方法接受两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点( previousSibling ),同时被方法返回。如果参照节点是null ,则 insertBefore() 与 appendChild() 执行相同的操作
- 1005、 replaceChild() 方法接受的两个参数是:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置
- 1006、如果只想移除而非替换节点,可以使用 removeChild() 方法。这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值
- 1007、要使用这几个方法必须先取得父节点(使用 parentNode 属性)。另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将会导致错误发生
- 1008、 cloneNode() ,用于创建调用这个方法的节点的一个完全相同的副本。 cloneNode() 方法接受一个布尔值参数,表示是否执行深复制
- 1009、cloneNode() 方法不会复制添加到 DOM 节点中的 JavaScript 属性,例如事件处理程序等。这个方法只复制特性、(在明确指定的情况下也复制)子节点,其他一切都不会复制。IE 在此存在一个 bug,即它会复制事件处理程序,所以我们建议在复制之前最好先移除事件处理程序
- 1010、最后一个方法是 normalize() ,这个方法唯一的作用就是处理文档树中的文本节点。由于解析器的实现或 DOM 操作等原因,可能会出现文本节点不包含文本,或者接连出现两个文本节点的情况。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种情况。如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点
- 1011、虽然 DOM 标准规定 Document 节点的子节点可以是 DocumentType 、 Element 、 ProcessingIn-struction 或 Comment ,但还有两个内置的访问其子节点的快捷方式。第一个就是 documentElement属性,该属性始终指向 HTML 页面中的 <html> 元素。另一个就是通过 childNodes 列表访问文档元素,但通过 documentElement 属性则能更快捷、更直接地访问该元素
- 1012、所有浏览器都支持 document.documentElement 和 document.body 属性
- 1013、作为 HTMLDocument 的一个实例, document 对象还有一些标准的 Document 对象所没有的属性。这些属性提供了 document 对象所表现的网页的一些信息。其中第一个属性就是 title ,包含着<title> 元素中的文本——显示在浏览器窗口的标题栏或标签页上。通过这个属性可以取得当前页面的标题,也可以修改当前页面的标题并反映在浏览器的标题栏中。修改 title 属性的值不会改变 <title>元素
- 1014、 URL 属性中包含页面完整的 URL(即地址栏中显示的 URL), domain 属性中只包含页面的域名,而 referrer属性中则保存着链接到当前页面的那个页面的 URL。在没有来源页面的情况下, referrer 属性中可能会包含空字符串。所有这些信息都存在于请求的 HTTP 头部,只不过是通过这些属性让我们能够在JavaScrip 中访问它们而已
- 1015、当页面中包含来自其他子域的框架或内嵌框架时,能够设置 document.domain 就非常方便了。由于 跨 域 安 全 限 制 , 来 自 不 同 子 域 的 页 面 无 法 通 过 JavaScript 通 信 。 而 通 过 将 每 个 页 面 的document.domain 设置为相同的值,这些页面就可以互相访问对方包含的 JavaScript 对象了
- 1016、假设有一个页面加载自 www.wrox.com,其中包含一个内嵌框架,框架内的页面加载自 p2p.wrox.com。由于 document.domain 字符串不一样,内外两个页面之间无法相互访问对方的 JavaScript 对象。但如果将这两个页面的 document.domain 值都设置为 "wrox.com" ,它们之间就可以通信了。浏览器对 domain 属性还有一个限制,即如果域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight)。换句话说,在将 document.domain 设置为 "wrox.com" 之后,就不能再将其设置回 "p2p.wrox.com" ,否则将会导致错误
- 1017、HTMLCollection 对象还有一个方法,叫做 namedItem() ,使用这个方法可以通过元素的 name特性取得集合中的项。对 HTMLCollection 而言,我们可以向方括号中传入数值或字符串形式的索引值。在后台,对数值索引就会调用 item() ,而对字符串索引就会调用 namedItem()
- 1018、有一个 document 对象的功能已经存在很多年了,那就是将输出流写入到网页中的能力。这个能力体现在下列 4 个方法中: write() 、 writeln() 、 open() 和 close() 。其中, write() 和 writeln()方法都接受一个字符串参数,即要写入到输出流中的文本。 write() 会原样写入,而 writeln() 则会在字符串的末尾添加一个换行符( n )。在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容
- 1019、方法 open() 和 close() 分别用于打开和关闭网页的输出流
- 1020、每个元素都有一或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。操作特性的DOM 方法主要有三个,分别是 getAttribute() 、 setAttribute() 和 removeAttribute()
- 1021、与 getAttribute() 对应的方法是 setAttribute() ,这个方法接受两个参数:要设置的特性名和值。如果特性已经存在, setAttribute() 会以指定的值替换现有的值;如果特性不存在, setAttribute()则创建该属性并设置相应的值
- 1022、 removeAttribute() ,这个方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性
- 1023、使用 document.createElement() 方法可以创建新元素。这个方法只接受一个参数,即要创建元素的标签名。这个标签名在 HTML 文档中不区分大小写,而在 XML(包括 XHTML)文档中,则是区分大小写的
- 1024、文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML 字符,但不能包含 HTML 代码
- 1025、可以使用 document.createTextNode() 创建新文本节点,这个方法接受一个参数——要插入节点中的文本
- 1026、使用 document.createComment() 并为其传递注释文本也可以创建注释节点
- 1027、虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点。要创建文档片段,可以使用 document.createDocumentFragment() 方法
- 1028、文档片段继承了 Node 的所有方法,通常用于执行那些针对文档的 DOM操作。如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。添加到文档片段中的新节点同样也不属于文档树。可以通过 appendChild() 或insertBefore() 将文档片段中内容添加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应位置上;文档片段本身永远不会成为文档树的一部分
- 1029、Attr 对象有 3 个属性: name 、 value 和 specified 。其中, name 是特性名称(与 nodeName 的值相同), value 是特性的值(与 nodeValue 的值相同),而 specified 是一个布尔值,用以区别特性是在代码中指定的,还是默认的
- 1030、理解 NodeList 及其“近亲” NamedNodeMap 和 HTMLCollection ,是从整体上透彻理解 DOM 的关键所在。这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。因此,它们始终都会保存着最新、最准确的信息。从本质上说,所有 NodeList 对象都是在访问 DOM文档时实时运行的查询
- 1031、一般来说,应该尽量减少访问 NodeList 的次数。因为每次访问 NodeList ,都会运行一次基于文档的查询。所以,可以考虑将从 NodeList 中取得的值缓存起来
- 1032、querySelector() 方法接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null 。
- 1033、querySelectorAll() 方法接收的参数与 querySelector() 方法一样,都是一个 CSS 选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个 NodeList 的实例
- 1034、如果传入了浏览器不支持的选择符或者选择符中有语法错误,querySelectorAll() 会抛出错误
- 1035、Selectors API Level 2 规范为 Element 类型新增了一个方法 matchesSelector() 。这个方法接收一个参数,即 CSS 选择符,如果调用元素与该选择符匹配,返回 true ;否则,返回 false
- 1036、对于元素间的空格,IE9及之前版本不会返回文本节点,而其他所有浏览器都会返回文本节点
- 1037、支持 getElementsByClassName() 方法的浏览器有 IE 9+、Firefox 3+、Safari 3.1+、Chrome 和Opera 9.5+
- 1038、新增了 document.hasFocus() 方法,这个方法用于确定文档是否获得了焦点
- 1039、使用 document.readyState 的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器。支持 readyState 属性的浏览器有 IE4+、Firefox 3.6+、Safari、Chrome和 Opera 9+
- 1040、自从 IE6 开始区分渲染页面的模式是标准的还是混杂的,检测页面的兼容模式就成为浏览器的必要功能。IE 为此给 document 添加了一个名为 compatMode 的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。就像下面例子中所展示的那样,在标准模式下, document.compatMode 的值等于 "CSS1Compat" ,而在混杂模式下, document.compatMode 的值等于 "BackCompat"。
- 1041、HTML5规定可以为元素添加非标准的属性,但要添加前缀 data- ,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以 data- 开头即可
- 1042、在读模式下, innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的 HTML 标记。在写模式下, innerHTML 会根据指定的值创建新的 DOM树,然后用这个 DOM 树完全替换调用元素原先的所有子节点
- 1043、在写模式下, innerHTML 的值会被解析为 DOM 子树,替换调用元素原来的所有子节点。因为它的值被认为是 HTML,所以其中的所有标签都会按照浏览器处理 HTML 的标准方式转换为元素(同样,这里的转换结果也因浏览器而异)。如果设置的值仅是文本而没有 HTML 标签,那么结果就是设置纯文本
- 1044、 innerHTML 字符串一开始(而且整个)就是一个“无作用域的元素”,所以这个字符串会变成空字符串
- 1045、不支持 innerHTML 的元素有:
<col> 、 <colgroup> 、<frameset> 、 <head> 、 <html> 、 <style> 、 <table> 、<tbody> 、<thead> 、<tfoot> 和 <tr>
。此外,在 IE8 及更早版本中, <title> 元素也没有 innerHTML 属性 - 1046、在读模式下, outerHTML 返回调用它的元素及所有子节点的 HTML 标签。在写模式下, outerHTML会根据指定的 HTML 字符串创建新的 DOM子树,然后用这个 DOM 子树完全替换调用元素。
- 1047、由于 IE9 之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此就出现了 children属性。这个属性是 HTMLCollection 的实例,只包含元素中同样还是元素的子节点。除此之外,children 属性与 childNodes 没有什么区别,即在元素只包含元素子节点时,这两个属性的值相同
- 1048、在实际开发中,经常需要知道某个节点是不是另一个节点的后代。调用 contains() 方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回 true ;否则,返回 false 。
- 1049、innerText 与 textContent 返回的内容并不完全一样。比如,innerText 会忽略行内的样式和脚本,而 textContent 则会像返回其他文本一样返回行内的样式和脚本代码。避免跨浏览器兼容问题的最佳途径,就是从不包含行内样式或行内脚本的 DOM 子树副本或 DOM 片段中读取文本
- 1050、scrollIntoViewIfNeeded(alignCenter) :只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。如果将可选的 alignCenter 参数设置为 true ,则表示尽量将元素显示在视口中部(垂直方向)。Safari 和 Chrome 实现了这个方法
- 1051、在标准模式下,所有度量值都必须指定一个度量单位。在混杂模式下,可以将style.width 设置为 "20" ,浏览器会假设它是 "20px" ;但在标准模式下,将style.width 设置为 "20" 会导致被忽略——因为没有度量单位。在实践中,最好始终都指定度量单位
- 1052、通过 cssText 属性可以访问style特性中的CSS代码。在读取模式下, cssText 返回浏览器对 style特性中 CSS 代码的内部表示。在写入模式下,赋给 cssText 的值会重写整个 style 特性的值;也就是说,以前通过 style 特性指定的样式信息都将丢失
- 1053、如果你需要更多信息,可以使用 getPropertyCSSValue() 方法,它返回一个包含两个属性的 CSSValue 对象,这两个属性分别是: cssText 和 cssValueType 。其中, cssText 属性的值与 getPropertyValue() 返回的值相同,而 cssValueType 属性则是一个数值常量,表示值的类型:0 表示继承的值,1 表示基本的值,2 表示值列表,3 表示自定义的值
- 1054、要从元素的样式中移除某个 CSS 属性,需要使用 removeProperty() 方法。使用这个方法移除一个属性,意味着将会为该属性应用默认的样式(从其他样式表经层叠而来)。例如,要移除通过 style特性设置的 border 属性
- 1055、 getComputedStyle() 方法返回一个 CSSStyleDeclaration 对象(与 style 属性的类型相同),其中包含当前元素的所有计算的样式。IE 不支持 getComputedStyle() 方法,但它有一种类似的概念。在 IE 中,每个具有 style 属性的元素还有一个 currentStyle 属性。这个属性是 CSSStyleDeclaration 的实例,包含当前元素全部计算后的样式
- 1056、无论在哪个浏览器中,最重要的一条是要记住所有计算的样式都是只读的;不能修改计算后样式对象中的 CSS 属性。此外,计算后的样式也包含属于浏览器内部样式表的样式信息,因此任何具有默认值的 CSS 属性都会表现在计算后的样式中。例如,所有浏览器中的 visibility 属性都有一个默认值,但这个值会因实现而异
- 1057、CSSStyleSheet 类型表示的是样式表,包括通过
<link>
元素包含的样式表和在<style>
元素中定义的样式表 - 1058、从样式表中删除规则的方法是 deleteRule() ,这个方法接受一个参数:要删除的规则的位置
- 1059、首先要介绍的属性涉及偏移量(offset dimension),包括元素在屏幕上占用的所有可见的空间。元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小(注意,不包括外边距)
- 1060、所有这些偏移量属性都是只读的,而且每次访问它们都需要重新计算。因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性的值,可以将它们保存在局部变量中,以提高性能。
第十一章 DOM扩展、第十二章 DOM2和DOM3
- 1101、querySelector() 方法接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null
- 1102、querySelectorAll() 方法接收的参数与 querySelector() 方法一样,都是一个 CSS 选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个 NodeList 的实例。返回的值实际上是带有所有属性和方法的 NodeList ,而其底层实现则类似于一组元素的快照,而非不断对文档进行搜索的动态查询
- 1103、childElementCount :返回子元素(不包括文本节点和注释)的个数;firstElementChild :指向第一个子元素; firstChild 的元素版;lastElementChild :指向最后一个子元素; lastChild 的元素版; previousElementSibling :指向前一个同辈元素; previousSibling 的元素版;nextElementSibling :指向后一个同辈元素; nextSibling 的元素版
- 1104、getElementsByClassName() 方法接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的 NodeList。传入多个类名时,类名的先后顺序不重要。因为返回的对象是 NodeList ,所以使用这个方法与使用 getElementsByTagName()。以及其他返回 NodeList 的 DOM 方法都具有同样的性能问题。支持 getElementsByClassName() 方法的浏览器有 IE 9+、Firefox 3+、Safari 3.1+、Chrome 和Opera 9.5+
- 1105、div.classList.remove("user") => add(value) :将给定的字符串值添加到列表中。如果值已经存在,就不添加了;contains(value) :表示列表中是否存在给定的值,如果存在则返回 true ,否则返回 false;remove(value) :从列表中删除给定的字符串;toggle(value) :如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。支持 classList 属性的浏览器有 Firefox 3.6+和 Chrome
- 1106、 document.activeElement 属性,这个属性始终会引用 DOM 中当前获得了焦点的元素。默认情况下,文档刚刚加载完成时, document.activeElement 中保存的是 document.body 元素的引用。文档加载期间, document.activeElement 的值为 null
- 1107、 document.hasFocus() 方法,这个方法用于确定文档是否获得了焦点。
- 1108、实现了这两个属性的浏览器的包括 IE 4+、Firefox 3+、Safari 4+、Chrome 和 Opera 8+
- 1109、使用 document.readyState 的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器
- 1110、在标准模式下, document.compatMode 的值等于 "CSS1Compat" ,而在混杂模式下, document.compatMode 的值等于 "BackCompat"
- 1111、HTML5 新增了 document.head 属性,引用文档的 <head> 元素。实现 document.head 属性的浏览器包括 Chrome 和 Safari 5
- 1112、HTML5规定可以为元素添加非标准的属性,但要添加前缀 data- ,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以 data- 开头即可
- 1113、添加了自定义属性之后,可以通过元素的 dataset 属性来访问自定义属性的值。 dataset 属性的值是 DOMStringMap 的一个实例,也就是一个名值对儿的映射。在这个映射中,每个 data-name 形式的属性都会有一个对应的属性,只不过属性名没有 data- 前缀(比如,自定义属性是 data-myname ,那映射中对应的属性就是 myname )
- 1114、在读模式下, innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的 HTML 标记。在写模式下, innerHTML 会根据指定的值创建新的 DOM树,然后用这个 DOM 树完全替换调用元素原先的所有子节点
- 1115、使用 innerHTML 属性也有一些限制。比如,在大多数浏览器中,通过 innerHTML 插入
<script>
元素并不会执行其中的脚本。IE8 及更早版本是唯一能在这种情况下执行脚本的浏览器,但必须满足一些条件。一是必须为<script>
元素指定 defer 属性,二是<script>
元素必须位于(微软所谓的)“有作用域的元素”(scoped element)之后。<script>
元素被认为是“无作用域的元素”(NoScope element),也就是在页面中看不到的元素,与<style>
元素或注释类似。如果通过 innerHTML 插入的字符串开头就是一个“无作用域的元素”,那么 IE 会在解析这个字符串前先删除该元素。div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');<\/script>"
- 1116、并不是所有元素都支持 innerHTML 属性。不支持 innerHTML 的元素有:
<col> 、 <colgroup> 、<frameset> 、 <head> 、 <html> 、 <style> 、 <table> 、 <tbody> 、 <thead> 、 <tfoot> 和 <tr>
。此外,在 IE8 及更早版本中, <title> 元素也没有 innerHTML 属性 - 1117、IE8 为此提供了 window.toStaticHTML() 方法,这个方法接收一个参数,即一个 HTML 字符串;返回一个经过无害处理后的版本——从源 HTML 中删除所有脚本节点和事件处理程序属性
- 1118、如果在<div>元素上调用outerHTML,会返回与上面相同的代码,包括<div>本身。支持outerHTML属性的浏览器有IE4+、Safari 4+、Chrome和Opera 8+。Firefox 7及之前版本都不支持outerHTML属性
- 1119、插入标记的最后一个新增方式是 insertAdjacentHTML() 方法。这个方法最早也是在IE中出现的,它接收两个参数:插入位置和要插入的 HTML 文本。"beforebegin" ,在当前元素之前插入一个紧邻的同辈元素;"afterbegin" ,在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;"beforeend" ,在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;"afterend" ,在当前元素之后插入一个紧邻的同辈元素。第二个参数是一个 HTML 字符串(与 innerHTML 和 outerHTML的值相同)。支持insertAdjacentHTML() 方法的浏览器有 IE、Firefox 8+、Safari、Opera 和 Chrome
- 1120、scrollIntoView() 可以在所有 HTML 元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。如果给这个方法传入 true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入 false 作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐)。支持 scrollIntoView() 方法的浏览器有 IE、Firefox、Safari 和 Opera
- 1121、children这个属性是 HTMLCollection 的实例,只包含元素中同样还是元素的子节点。除此之外,children 属性与 childNodes 没有什么区别,即在元素只包含元素子节点时,这两个属性的值相同。支持 children 属性的浏览器有 IE5、Firefox 3.5、Safari 2(但有 bug)、Safari 3(完全支持)、Opera8和 Chrome(所有版本)。IE8 及更早版本的 children 属性中也会包含注释节点,但 IE9 之后的版本则只返回元素节点
- 1122、调用 contains() 方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回 true ;否则,返回 false。支持 contains() 方法的浏览器有 IE、Firefox 9+、Safari、Opera 和 Chrome
- 1123、多数情况下,都可以通过简单地转换属性名的格式来实现转换。其中一个不能直接转换的 CSS 属性就是 float 。由于 float 是 JavaScript 中的保留字,因此不能用作属性名。“DOM2 级样式”规范规定样式对象上相应的属性名应该是 cssFloat ;Firefox、Safari、Opera 和 Chrome 都支持这个属性,而 IE支持的则是 styleFloat
- 1124、通过 cssText 属性可以访问style特性中的CSS代码。在读取模式下, cssText 返回浏览器对 style特性中 CSS 代码的内部表示。在写入模式下,赋给 cssText 的值会重写整个 style 特性的值;也就是说,以前通过 style 特性指定的样式信息都将丢失
- 1125、getPropertyValue() 方法取得的始终都是 CSS 属性值的字符串表示。如果你需要更多信息,可以使用 getPropertyCSSValue() 方法,它返回一个包含两个属性的 CSSValue 对象,这两个属性分别是: cssText 和 cssValueType 。其中, cssText 属性的值与getPropertyValue() 返回的值相同,而 cssValueType 属性则是一个数值常量,表示值的类型:0 表示继承的值,1 表示基本的值,2 表示值列表,3 表示自定义的值。在实际开发中, getPropertyCSSValue() 使用得比 getPropertyValue() 少得多。IE9+、Safarie3+以及 Chrome 支持这个方法。Firefox 7 及之前版本也提供这个访问,但调用总返回 null
- 1126、要从元素的样式中移除某个 CSS 属性,需要使用 removeProperty() 方法。使用这个方法移除一个属性,意味着将会为该属性应用默认的样式(从其他样式表经层叠而来)
- 1127、getComputedStyle() 方法。这个方法接受两个参数:要取得计算样式的元素和一个伪元素字符串(例如 ":after" )。如果不需要伪元素信息,第二个参数可以是 null 。 getComputedStyle() 方法返回一个 CSSStyleDeclaration 对象(与 style 属性的类型相同),其中包含当前元素的所有计算的样式。IE 不支持 getComputedStyle() 方法,但它有一种类似的概念。在 IE 中,每个具有 style 属性的元素还有一个 currentStyle 属性。这个属性是 CSSStyleDeclaration 的实例,包含当前元素全部计算后的样式。与 DOM 版本的方式一样,IE 也没有返回 border 样式,因为这是一个综合属性。无论在哪个浏览器中,最重要的一条是要记住所有计算的样式都是只读的;不能修改计算后样式对象中的 CSS 属性。此外,计算后的样式也包含属于浏览器内部样式表的样式信息,因此任何具有默认值的 CSS 属性都会表现在计算后的样式中
- 1128、CSSStyleSheet 类型表示的是样式表,包括通过 <link> 元素包含的样式表和在
<style>
元素中定义的样式表。有读者可能记得,这两个元素本身分别是由 HTMLLinkElement 和 HTMLStyleElement 类型表示的。但是, CSSStyleSheet 类型相对更加通用一些,它只表示样式表,而不管这些样式表在 HTML中是如何定义的。此外,上述两个针对元素的类型允许修改 HTML特性,但 CSSStyleSheet 对象则是一套只读的接口(有一个属性例外)。disabled :表示样式表是否被禁用的布尔值。这个属性是可读/写的,将这个值设置为 true 可以禁用样式表 - 1129、其中三个最常用的属性是 cssText 、 selectorText 和 style 。 cssText 属性与 style.cssText属性类似,但并不相同。前者包含选择符文本和围绕样式信息的花括号,后者只包含样式信息(类似于元素的 style.cssText )。此外, cssText 是只读的,而 style.cssText 也可以被重写
- 1130、 insertRule() 方法接受两个参数:规则文本和表示在哪里插入规则的索引。Firefox、Safari、Opera 和 Chrome都支持 insertRule() 方法。IE8 及更早版本支持一个类似的方法,名叫 addRule() ,也接收两必选参数:选择符文本和 CSS样式信息;一个可选参数:插入规则的位置
- 1131、从样式表中删除规则的方法是 deleteRule() ,这个方法接受一个参数:要删除的规则的位置;IE 支持的类似方法叫 removeRule() ,使用方法相同。与添加规则相似,删除规则也不是实际 Web 开发中常见的做法。考虑到删除规则可能会影响 CSS层叠的效果,因此请大家慎重使用
- 1132、偏移量。offsetHeight :元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度;offsetWidth :元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度;offsetLeft :元素的左外边框至包含元素的左内边框之间的像素距离;offsetTop :元素的上外边框至包含元素的上内边框之间的像素距离。要想知道某个元素在页面上的偏移量,将这个元素的 offsetLeft 和 offsetTop 与其 offsetParent的相同属性相加,如此循环直至根元素,就可以得到一个基本准确的值
- 1133、所有这些偏移量属性都是只读的,而且每次访问它们都需要重新计算。因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性的值,可以将它们保存在局部变量中,以提高性能
- 1134、元素的客户区大小(client dimension),指的是元素内容及其内边距所占据的空间大小。有关客户区大小的属性有两个: clientWidth 和 clientHeight 。其中, clientWidth 属性是元素内容区宽度加上左右内边距宽度; clientHeight 属性是元素内容区高度加上上下内边距高度。注意这两个属性不包含边框(border)
- 1135、与偏移量相似,客户区大小也是只读的,也是每次访问都要重新计算的
- 1136、有些元素(例如<html> 元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过 CSS 的overflow 属性进行设置才能滚动。scrollHeight :在没有滚动条的情况下,元素内容的总高度;scrollWidth :在没有滚动条的情况下,元素内容的总宽度;scrollLeft :被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置;scrollTop :被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置
- 1137、对于 不 包含 滚动 条 的页 面而 言 , scrollWidth 和 scrollHeight 与 clientWidth 和clientHeight 之间的关系并不十分清晰
- 1138、在确定文档的总高度时(包括基于视口的最小高度时),必须取得 scrollWidth/clientWidth 和scrollHeight/clientHeight 中的最大值,才能保证在跨浏览器的环境下得到精确的结果
- 1139、通过 scrollLeft 和 scrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置。在元素尚未被滚动时,这两个属性的值都等于 0。如果元素被垂直滚动了,那么 scrollTop 的值会大于 0,且表示元素上方不可见内容的像素高度。如果元素被水平滚动了,那么 scrollLeft 的值会大于 0,且表示元素左侧不可见内容的像素宽度。这两个属性都是可以设置的,因此将元素的scrollLeft 和 scrollTop 设置为 0,就可以重置元素的滚动位置
- 1140、IE、Firefox 3+、Safari 4+、Opera 9.5及 Chrome为每个元素都提供了一个 getBoundingClientRect() 方法。这个方法返回会一个矩形对象,包含 4 个属性: left 、 top 、 right 和 bottom 。这些属性给出了元素在页面中相对于视口的位置。但是,浏览器的实现稍有不同。IE8 及更早版本认为文档的左上角坐标是(2, 2),而其他浏览器包括 IE9 则将传统的(0,0)作为起点坐标。因此,就需要在一开始检查一下位于(0,0)处的元素的位置,在 IE8 及更早版本中,会返回(2,2),而在其他浏览器中会返回(0,0)
- 1141、对于不支持 getBoundingClientRect() 的浏览器,可以通过其他手段取得相同的信息。一般来说, right 和 left 的差值与 offsetWidth 的值相等,而 bottom 和 top 的差值与 offsetHeight相等。而且, left 和 top 属性大致等于使用本章前面定义的 getElementLeft() 和 getElementTop()函数取得的值
- 1142、DOM2 级在 Document 类型中定义了 createRange() 方法。在兼容 DOM 的浏览器中,这个方法属于 document 对象。使用 hasFeature() 或者直接检测该方法,都可以确定浏览器是否支持范围
- 1143、要使用范围来选择文档中的一部分,最简的方式就是使用 selectNode() 或 selectNodeContents() 。这两个方法都接受一个参数,即一个 DOM 节点,然后使用该节点中的信息来填充范围。其中,selectNode() 方法选择整个节点,包括其子节点;而 selectNodeContents() 方法则只选择节点的子节点
- 1144、要创建复杂的范围就得使用 setStart() 和 setEnd() 方法。这两个方法都接受两个参数:一个参照节点和一个偏移量值。对 setStart() 来说,参照节点会变成 startContainer ,而偏移量值会变成startOffset 。对于 setEnd() 来说,参照节点会变成 endContainer ,而偏移量值会变成 endOffset
- 1145、使用 insertNode()方法可以向范围选区的开始处插入一个节点。
<span>
正好被插入到了 "Hello" 中的 "llo" 前面,而该位置就是范围选区的开始位置。还要注意的是,由于这里没有使用上一节介绍的方法,结果原始的 HTML 并没有添加或删除<b>
元素。使用这种技术可以插入一些帮助提示信息,例如在打开新窗口的链接旁边插入一幅图像 - 1146、除了向范围内部插入内容之外,还可以环绕范围插入内容,此时就要使用 surroundContents()方法。这个方法接受一个参数,即环绕范围内容的节点。在环绕范围插入内容时,后台会执行下列步骤:提取出范围中的内容(类似执行 extractContent() );将给定节点插入到文档中原来范围所在的位置上;将文档片段的内容添加到给定节点中
- 1147、所谓折叠范围,就是指范围中未选择文档的任何部分。使用 collapse() 方法来折叠范围,这个方法接受一个参数,一个布尔值,表示要折叠到范围的哪一端。参数 true 表示折叠到范围的起点,参数 false 表示折叠到范围的终点。要确定范围已经折叠完毕,可以检查 collapsed 属性
- 1148、可以使用 cloneRange() 方法复制范围。这个方法会创建调用它的范围的一个副本。新创建的范围与原来的范围包含相同的属性,而修改它的端点不会影响原来的范围
- 1149、在使用完范围之后,最好是调用 detach() 方法,以便从创建范围的文档中分离出该范围。调用detach() 之后,就可以放心地解除对范围的引用,从而让垃圾回收机制回收其内存了
- 1150、IE9、Firefox、Opera、Safari 和 Chrome 全都已经实现了“DOM2 级事件”模块的核心部分。IE8 是最后一个仍然使用其专有事件系统的主要浏览器
第十三章 事件
- 1301、事件流描述的是从页面中接收事件的顺序。但有意思的是,IE 和 Netscape 开发团队居然提出了差不多是完全相反的事件流的概念。IE 的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事件捕获流
- 1302、IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)
- 1303、Netscape Communicator团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它
- 1304、虽然事件捕获是 Netscape Communicator 唯一支持的事件流模型,但 IE9、Safari、Chrome、Opera和 Firefox 目前也都支持这种事件流模型。尽管“DOM2 级事件”规范要求事件应该从 document 对象开始传播,但这些浏览器都是从 window 对象开始捕获事件的。
- 1305、由于老版本的浏览器不支持,因此很少有人使用事件捕获。我们也建议读者放心地使用事件冒泡,在有特殊需要时再使用事件捕获
- 1306、“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应
- 1307、在 DOM 事件流中,实际的目标( <div> 元素)在捕获阶段不会接收到事件
- 1308、多数支持 DOM事件流的浏览器都实现了一种特定的行为;即使“DOM2 级事件”规范明确要求捕获阶段不会涉及事件目标,但 IE9、Safari、Chrome、Firefox 和 Opera 9.5 及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上面操作事件。IE9、Opera、Firefox、Chrome 和 Safari 都支持 DOM 事件流;IE8 及更早版本不支持 DOM 事件流。
- 1309、将事件处理程序设置为 null 之后,再单击按钮将不会有任何动作发生
- 1310、“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener()和 removeEventListener() 。所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true ,表示在捕获阶段调用事件处理程序;如果是 false ,表示在冒泡阶段调用事件处理程序
- 1311、通过 addEventListener() 添加的事件处理程序只能使用 removeEventListener() 来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener() 添加的匿名函数将无法移除。把传入的匿名函数赋给一个变量,在添加事件监听或移除事件监听使用该变量可以移除
- 1312、大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序
- 1313、IE 实现了与 DOM 中类似的两个方法: attachEvent() 和 detachEvent() 。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过attachEvent() 添加的事件处理程序都会被添加到冒泡阶段。注意, attachEvent() 的第一个参数是 "onclick" ,而非 DOM 的 addEventListener() 方法中的 "click"
- 1314、在 IE 中使用 attachEvent() 与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window
- 1315、这里调用了两次 attachEvent() ,为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发
- 1316、使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给 detachEvent() ,就可以移除相应的事件处理程序
- 1317、在触发 DOM 上的某个事件时,会产生一个事件对象 event ,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。例如,鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含与按下的键有关的信息。所有浏览器都支持 event 对象,但支持方式不同
- 1318、在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this 、 currentTarget 和 target 包含相同的值。如果事件处理程序存在于按钮的父节点中(例如 document.body ),那么这些值是不相同的
- 1319、事件委托是通过事件冒泡来实现的
- 1320、要阻止特定事件的默认行为,可以使用 preventDefault() 方法。例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick 事件处理程序可以取消它
- 1321、只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault() 来取消其默认行为
- 1322、 stopPropagation() 方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡
- 1323、事件对象的eventPhase属性,可以用来确定事件当前正位于事件流的哪个阶段。如果是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1 ;如果事件处理程序处于目标对象上,则event-Phase等于2;如果是在冒泡阶段调用的事件处理程序, eventPhase 等于 3
- 1324、只有在事件处理程序执行期间, event 对象才会存在;一旦事件处理程序执行完成, event 对象就会被销毁
- 1325、 returnValue 属性相当于 DOM中的 preventDefault() 方法,它们的作用都是取消给定事件的默认行为。只要将 returnValue 设置为 false ,就可以阻止默认行为
- 1326、cancelBubble 属性与 DOM 中的 stopPropagation() 方法作用相同,都是用来停止事件冒泡的。由于 IE 不支持事件捕获,因而只能取消事件冒泡;但 stopPropagatioin() 可以同时取消事件捕获和冒泡
- 1327、在 onclick 事件处理程序中将 cancelBubble 设置为 true ,就可阻止事件通过冒泡而触发document.body 中注册的事件处理程序
- 1328、JavaScript 中最常用的一个事件就是 load 。当页面完全加载后(包括所有图像、JavaScript 文件、CSS 文件等外部资源),就会触发 window 上面的 load 事件
- 1329、与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件
- 1330、当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window (窗口)上面触发,因此可以通过 JavaScript 或者 <body> 元素中的 onresize 特性来指定事件处理程序
- 1331、关于何时会触发 resize 事件,不同浏览器有不同的机制。IE、Safari、Chrome 和 Opera 会在浏览器窗口变化了 1 像素时就触发 resize 事件,然后随着变化不断重复触发。Firefox 则只会在用户停止调整窗口大小时才会触发 resize 事件。由于存在这个差别,应该注意不要在这个事件的处理程序中加入大计算量的代码,因为这些代码有可能被频繁执行,从而导致浏览器反应明显变慢。浏览器窗口最小化或最大化时也会触发 resize 事件
- 1332、焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及document.activeElement 属性配合,可以知晓用户在页面上的行踪
- 1333、 focus 和 blur ,它们都是 JavaScript 早期就得到所有浏览器支持的事件。这些事件的最大问题是它们不冒泡。因此,IE 的 focusin 和 focusout 与 Opera 的 DOMFocusIn和 DOMFocusOut 才会发生重叠。IE 的方式最后被 DOM3 级事件采纳为标准方式
- 1334、鼠标事件中还有一类滚轮事件。而说是一类事件,其实就是一个 mousewheel 事件。这个事件跟踪鼠标滚轮,类似于 Mac 的触控板
- 1335、鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的 clientX 和clientY 属性中。所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。注意,这些值中不包括页面滚动的距离,因此这个位置并不表示鼠标在页面上的位置。
- 1336、页面坐标通过事件对象的pageX和pageY属性,能告诉你事件是在页面中的什么位置发生的。换句话说,这两个属性表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的
- 1337、IE8 及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。这时候需要用到 document.body (混杂模式)或 document.documentElement (标准模式)中的scrollLeft 和 scrollTop 属性
- 1338、通过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息
- 1339、虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。这些修改键就是 Shift、Ctrl、Alt 和 Meta(在 Windows键盘中是 Windows键,在苹果机中是 Cmd 键),它们经常被用来修改鼠标事件的行为。DOM 为此规定了 4 个属性,表示这些修改键的状态: shiftKey 、 ctrlKey 、 altKey 和 metaKey 。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为 true ,否则值为 false 。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否同时按下了其中的键
- 1340、DOM通过 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover和 mouseout 事件才包含值;对于其他事件,这个属性的值是 null
- 1341、只有在主鼠标按钮被单击(或键盘回车键被按下)时才会触发 click事件,因此检测按钮的信息并不是必要的。但对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性,表示按下或释放的按钮。DOM 的 button 属性可能有如下 3 个值: 0 表示主鼠标按钮, 1 表示中间的鼠标按钮(鼠标滚轮按钮), 2 表示次鼠标按钮
- 1342、“DOM2 级事件”规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息。对于鼠标事件来说, detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上相继地发生一次 mousedown 和一次 mouseup 事件算作一次单击。 detail 属性从 1 开始计数,每次单击发生后都会递增
- 1343、IE 6.0 首先实现了 mousewheel 事件。此后,Opera、Chrome 和 Safari 也都实现了这个事件。当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel事件。这个事件可以在任何元素上面触发,最终会冒泡到 document (IE8)或 window (IE9、Opera、Chrome 及 Safari)对象。与 mousewheel 事件对应的 event 对象除包含鼠标事件的所有标准信息外,还包含一个特殊的 wheelDelta 属性。当用户向前滚动鼠标滚轮时, wheelDelta 是 120 的倍数;当用户向后滚动鼠标滚轮时, wheelDelta 是120 的倍数。
- 1344、多数情况下,只要知道鼠标滚轮滚动的方向就够了,而这通过检测 wheelDelta 的正负号就可以确定。有一点要注意:在 Opera 9.5 之前的版本中, wheelDelta 值的正负号是颠倒的。如果你打算支持早期的 Opera 版本,就需要使用浏览器检测技术来确定实际的值
- 1345、键盘事件keydown、keypress、keyup与鼠标事件一样,都支持相同的修改键。而且,键盘事件的事件对象中也有 shiftKey 、 ctrlKey 、 altKey 和 metaKey 属性。IE 不支持 metaKey
- 1346、键码在发生 keydown 和 keyup 事件时, event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。对数字字母字符键, keyCode 属性的值与 ASCII 码中对应小写字母或数字的编码相同
- 1347、发生 keypress 事件意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress 事件;按下其他键能否触发此事件因浏览器而异
- 1348、IE8及之前版本和Opera则是在 keyCode 中保存字符的ASCII编码。要想以跨浏览器的方式取得字符编码,必须首先检测 charCode 属性是否可用,如果不可用则使用 keyCode。在取得了字符编码之后,就可以使用 String.fromCharCode() 将其转换成实际的字符
- 1349、尽管所有浏览器都实现了某种形式的键盘事件,DOM3 级事件还是做出了一些改变。比如,DOM3级事件中的键盘事件,不再包含 charCode 属性,而是包含两个新属性: key 和 char。其中, key 属性是为了取代 keyCode 而新增的,它的值是一个字符串。在按下某个字符键时, key的值就是相应的文本字符(如“k”或“M”);在按下非字符键时, key 的值是相应键的名(如“Shift”或“Down”)。而 char 属性在按下字符键时的行为与 key 相同,但在按下非字符键时值为 null。由于存在跨浏览器问题,因此本书不推荐使用 key 、 keyIdentifier 或 char
- 1350、 event 对象上还有一个属性,叫 inputMethod ,表示把文本输入到文本框中的方式。 1,表示是使用键盘输入的;2,表示文本是粘贴进来的; 3,表示文本是拖放进来的; 7,表示文本是通过语音输入的
- 1351、支持 textInput 属性的浏览器有 IE9+、Safari 和 Chrome。只有 IE 支持 inputMethod 属性
- 1352、在所有浏览器中都可以取消这个事件:在兼容 DOM 的浏览器中,使用 event.preventDefalut() ;在 IE 中,将 event.returnValue 的值设置为 false 。因为 contextmenu 事件属于鼠标事件,所以其事件对象中包含与光标位置有关的所有属性。通常使用 contextmenu 事件来显示自定义的上下文菜单,而使用 onclick 事件处理程序来隐藏该菜单。支持 contextmenu 事件的浏览器有 IE、Firefox、Safari、Chrome 和 Opera 11+
- 1353、之所以有发生在 window 对象上的 beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作。这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面了。为此,这个事件的意图是将控制权交给用户。显示的消息会告知用户页面行将被卸载(正因为如此才会显示这个消息),询问用户是否真的要关闭页面,还是希望继续留下来。IE 和 Firefox、Safari 和 Chrome 都支持 beforeunload 事件,也都会弹出这个对话框询问用户是否真想离开。Opera 11 及之前的版本不支持 beforeunload 事件
- 1354、touchstart :当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。touchmove :当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用 preventDefault()可以阻止滚动。touchend :当手指从屏幕上移开时触发。touchcancel :当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。上面这几个事件都会冒泡,也都可以取消
- 1355、gesturestart :当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。gesturechange :当触摸屏幕的任何一个手指的位置发生变化时触发。gestureend :当任何一个手指从屏幕上面移开时触发。
- 1356、事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。使用事件委托,只需在DOM 树中尽量最高的层次上添加一个事件处理程序。最适合采用事件委托技术的事件包括 click 、 mousedown 、 mouseup 、 keydown 、 keyup 和 keypress 。虽然 mouseover 和 mouseout 事件也冒泡,但要适当处理它们并不容易,而且经常需要计算元素的位置
- 1357、第一种情况就是从文档中移除带有事件处理程序的元素时。这可能是通过纯粹的 DOM 操作,例如使用 removeChild() 和 replaceChild() 方法,但更多地是发生在使用 innerHTML 替换页面中某一部分的时候。如果带有事件处理程序的元素被 innerHTML 删除了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收;导致“空事件处理程序”的另一种情况,就是卸载页面的时候
第十四章 表单脚本
- 1401、在以调用 submit() 方法的形式提交表单时,不会触发 submit 事件,因此要记得在调用此方法之前先验证表单数据
- 1402、提交表单时可能出现的最大问题,就是重复提交表单。在第一次提交表单后,如果长时间没有反应,用户可能会变得不耐烦。这时候,他们也许会反复单击提交按钮。结果往往很麻烦(因为服务器要处理重复的请求),或者会造成错误(如果用户是下订单,那么可能会多订好几份)。解决这一问题的办法有两个:在第一次提交表单后就禁用提交按钮,或者利用 onsubmit 事件处理程序取消后续的表单提交操作
- 1403、每个表单都有elements 属性,该属性是表单中所有表单元素(字段)的集合。这个 elements 集合是一个有序列表,其中包含着表单中的所有字段,例如
<input> 、 <textarea> 、 <button> 和 <fieldset>
。每个表单字段在 elements 集合中的顺序,与它们出现在标记中的顺序相同,可以按照位置和 name 特性来访问它们。如果有多个表单控件都在使用一个 name (如单选按钮),那么就会返回以该 name 命名的一个NodeList - 1404、很多用户可能会重复单击表单的提交按钮。在涉及信用卡消费时,这就是个问题:因为会导致费用翻番。为此,最常见的解决方案,就是在第一次单击后就禁用提交按钮。只要侦听 submit 事件,并在该事件发生时禁用提交按钮即可
- 1405、HTML5 为表单字段新增了一个 autofocus 属性。在支持这个属性的浏览器中,只要设置这个属性,不用 JavaScript 就能自动把焦点移动到相应字段
- 1406、在默认情况下,只有表单字段可以获得焦点。对于其他元素而言,如果先将其tabIndex 属性设置为1,然后再调用 focus() 方法,也可以让这些元素获得焦点。只有 Opera 不支持这种技术
- 1407、关于 blur 和 change 事件的关系,并没有严格的规定。在某些浏览器中, blur事件会先于 change 事件发生;而在其他浏览器中,则恰好相反。为此,不能假定这两个事件总会以某种顺序依次触发,这一点要特别注意
- 1408、要表现文本框,必须将
<input>
元素的 type 特性设置为 "text" 。而通过设置 size 特性,可以指定文本框中能够显示的字符数。通过 value 特性,可以设置文本框的初始值,而 maxlength 特性则用于指定文本框可以接受的最大字符数 - 1409、
<textarea>
元素则始终会呈现为一个多行文本框。要指定文本框的大小,可以使用 rows和 cols 特性。其中, rows 特性指定的是文本框的字符行数,而 cols 特性指定的是文本框的字符列数(类似于<inpu>
元素的 size 特性)。与<input>
元素不同,<textarea>
的初始值必须要放在<textarea>
和</textarea>
之间 - 1410、 select() 方法,这个方法用于选择文本框中的所有文本。在调用 select()方法时,大多数浏览器(Opera 除外)都会将焦点设置到文本框中。这个方法不接受参数,可以在任何时候被调用
420、 select 事件。在选择了文本框中的文本时,就会触发 select事件。不过,到底什么时候触发 select 事件,还会因浏览器而异。在 IE9+、Opera、Firefox、Chrome和 Safari 中,只有用户选择了文本(而且要释放鼠标),才会触发 select 事件。而在 IE8 及更早版本中,只要用户选择了一个字母(不必释放鼠标),就会触发 select 事件。另外,在调用 select() 方法时也会触发 select 事件
- 1411、取得选择的文本。HTML5 通过一些扩展方案解决了这个问题,以便更顺利地取得选择的文本。该规范采取的办法是添加两个属性: selectionStart 和 selectionEnd 。这两个属性中保存的是基于 0 的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)
- 1412、HTML5也为选择文本框中的部分文本提供了解决方案 , 即 最 早 由 Firefox 引 入 的setSelectionRange() 方法。现在除 select() 方法之外,所有文本框都有一个 setSelectionRange()方法。这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引(类似于 substring() 方法的两个参数)
- 1413、 clipboardData 对象有三个方法: getData() 、 setData() 和 clearData() 。其中, getData()用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式; setData() 方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文本
- 1414、任何标注有 required 的字段,在提交表单时都不能空着。这个属性适用于
<input> 、 <textarea>和 <select>
字段(Opera 11 及之前版本还不支持<select>
的 required 属性)。在 JavaScript 中,通过对应的 required 属性,可以检查某个表单字段是否为必填字段 - 1415、HTML5 为文本字段新增了 pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的值
- 1416、使用 checkValidity() 方法可以检测表单中的某个字段是否有效。所有表单字段都有个方法,如果字段的值有效,这个方法返回 true ,否则返回 false 。字段的值是否有效的判断依据是本节前面介绍过的那些约束。换句话说,必填字段中如果没有值就是无效的,而字段中的值与 pattern 属性不匹配也是无效的
- 1417、要检测整个表单是否有效,可以在表单自身调用 checkValidity() 方法。如果所有表单字段都有效,这个方法返回 true ;即使有一个字段无效,这个方法也会返回 false
- 1418、对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的 selectedIndex 属性
- 1419、与 selectedIndex 不同,在允许多选的选择框中设置选项的 selected 属性,不会取消对其他选中项的选择,因而可以动态选中任意多个项。但是,如果是在单选选择框中,修改某个选项的 selected 属性则会取消对其他选项的选择。需要注意的是,将 selected 属性设置为 false 对单选选择框没有影响
- 1420、 contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素。document.body.contentEditable='true'
第十五章 使用canvas绘图
第十六章 HTML5脚本编程
第十七章 错误处理与调试
- 1701、在 IE7 及更早版本中,如果错误发生在位于外部文件的脚本中,行号通常会与错误所在的行号差 1。如果是嵌入在页面中的脚本发生错误,则行号就是错误所在的行号
- 1702、ECMA-262 第 3 版引入了 try-catch 语句,作为 JavaScript 中处理异常的一种标准方式。也就是说,我们应该把所有可能会抛出错误的代码都放在 try 语句块中,而把那些用于错误处理的代码放在 catch 块中。如果 try 块中的任何代码发生了错误,就会立即退出代码执行过程,然后接着执行 catch 块。此时, catch 块会接收到一个包含错误信息的对象。与在其他语言中不同的是,即使你不想使用这个错误对象,也要给它起个名字。这个对象中包含的实际信息会因浏览器而异,但共同的是有一个保存着错误消息的 message 属性。ECMA-262 还规定了一个保存错误类型的 name 属性;当前所有浏览器都支持这个属性(Opera 9 之前的版本不支持这个属性)。因此,在发生错误时,就可以像下面这样实事求是地显示浏览器给出的消息
- 1703、只要代码中包含 finally 子句,那么无论 try 还是 catch 语句块中的 return 语句都将被忽略。因此,在使用 finally 子句之前,一定要非常清楚你想让代码怎么样
- 1704、TypeError 类型在 JavaScript 中会经常用到,在变量中保存着意外的类型时,或者在访问不存在的方法时,都会导致这种错误。错误的原因虽然多种多样,但归根结底还是由于在执行特定于类型的操作时,变量的类型并不符合要求所致
- 1705、使用 try-catch 最适合处理那些我们无法控制的错误。假设你在使用一个大型 JavaScript 库中的函数,该函数可能会有意无意地抛出一些错误。由于我们不能修改这个库的源代码,所以大可将对该函数的调用放在 try-catch 语句当中,万一有什么错误发生,也好恰当地处理它们
- 1706、在遇到 throw 操作符时,代码会立即停止执行。仅当有 try-catch 语句捕获到被抛出的值时,代码才会继续执行
437、利用原型链还可以通过继承 Error 来创建自定义错误类型(原型链在第 6 章中介绍)。此时,需要为新创建的错误类型指定 name 和 message 属性
- 1707、说到抛出错误与捕获错误,我们认为只应该捕获那些你确切地知道该如何处理的错误。捕获错误的目的在于避免浏览器以默认方式处理它们;而抛出错误的目的在于提供错误发生具体原因的消息
- 1708、图像也支持 error 事件。只要图像的 src 特性中的 URL 不能返回可以被识别的图像格式,就会触发 error 事件。此时的 error 事件遵循 DOM格式,会返回一个以图像为目标的 event 对象
- 1709、通过在 for 循环中添加 try-catch 语句,任何模块初始化时出错,都不会影响其他模块的初始化。在以上重写的代码中,如果有错误发生,相应的错误将会得到独立的处理,并不会影响到用户的体验
- 1710、console对象具有下列方法:error(message) :将错误消息记录到控制台;info(message) :将信息性消息记录到控制台;log(message) :将一般消息记录到控制台;warn(message) :将警告消息记录到控制台
- 1711、还有一种方案是使用 LiveConnect,也就是在 JavaScript 中运行 Java 代码。Firefox、Safari 和 Opera都支持 LiveConnect,因此可以操作 Java 控制台:java.lang.System.out.println("Your message")
- 1712、记录消息要比使用 alert() 函数更可取,因为警告框会阻断程序的执行,而在测定异步处理对时间的影响时,使用警告框会影响结果
- 1713、抛出错误例子:throw new Error("divide(): Both arguments must be numbers.")
- 1714、在可能发生错误的地方使用 try-catch 语句,这样你还有机会以适当的方式对错误给出响应,而不必沿用浏览器处理错误的机制
- 1715、使用 window.onerror 事件处理程序,这种方式可以接受 try-catch 不能处理的所有错误(仅限于 IE、Firefox 和 Chrome)
第十八章 JavaScript 与 XML
第十九章 E4X
第二十章 JSON
- 2001、JavaScript 字符串与 JSON 字符串的最大区别在于,JSON 字符串必须使用双引号(单引号会导致语法错误)
- 2002、JSON 中的对象要求给属性加引号
- 2003、JSON 中没有变量的概念
- 2004、JSON没有末尾的分号
- 2005、 eval() 函数可以解析、解释并返回 JavaScript 对象和数组
- 2006、JSON 对象有两个方法: stringify() 和 parse() 。在最简单的情况下,这两个方法分别用于把JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值
- 2007、将 JSON 字符串直接传递给 JSON.parse() 就可以得到相应的 JavaScript 值
- 2008、 JSON.stringify() 除了要序列化的 JavaScript 对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化 JavaScript 对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进
- 2009、有时候, JSON.stringify() 还是不能满足对某些对象进行自定义序列化的需求。在这些情况下,可以给对象定义 toJSON() 方法,返回其自身的 JSON 数据格式
第二十一章 Ajax 与 Comet
- 2101、在使用 XHR 对象时,要调用的第一个方法是 open() ,它接受 3 个参数:要发送的请求的类型( "get" 、 "post" 等)、请求的 URL 和表示是否异步发送请求的布尔值
- 2102、要发送特定的请求,必须调用 send() 方法。这里的 send() 方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入 null ,因为这个参数对有些浏览器来说是必需的。调用 send() 之后,请求就会被分派到服务器
- 2103、调用 XHR 对象的 getResponseHeader() 方法并传入头部字段名称,可以取得相应的响应头部信息。而调用 getAllResponseHeaders() 方法则可以取得一个包含所有头部信息的长字符串
- 2104、使用 GET 请求经常会发生的一个错误,就是查询字符串的格式有问题。查询字符串中每个参数的名称和值都必须使用 encodeURIComponent() 进行编码,然后才能放到 URL 的末尾;而且所有名-值对儿都必须由和号(&)分隔
- 2105、 POST 请求应该把数据作为请求的主体提交,而 GET 请求传统上不是这样。 POST 请求的主体可以包含非常多的数据,而且格式不限
- 2106、如果不设置 Content-Type 头部信息,那么发送给服务器的数据就不会出现在 $_POST 超级全局变量中。这时候,要访问同样的数据,就必须借助 $HTTP_RAW_POST_DATA
- 2107、与 GET 请求相比, POST 请求消耗的资源会更多一些。从性能角度来看,以发送相同的数据计, GET 请求的速度最多可达到 POST 请求的两倍
- 2108、XMLHttpRequest 2 级为此定义了FormData 类型。 FormData 为序列化表单以及创建与表单格式相同的数据(用于通过 XHR 传输)提供了便利
- 2109、使用 FormData 的方便之处体现在不必明确地在 XHR 对象上设置请求头部。XHR 对象能够识别传入的数据类型是 FormData 的实例,并配置适当的头部信息
- 2110、支持 FormData 的浏览器有 Firefox 4+、Safari 5+、Chrome 和 Android 3+版 WebKit
- 2111、IE8 为 XHR 对象添加了一个 timeout 属性,表示请求在等待响应多少毫秒之后就终止。在给timeout 设置一个数值后,如果在规定的时间内浏览器还没有接收到响应,那么就会触发 timeout 事件,进而会调用 ontimeout 事件处理程序。这项功能后来也被收入了 XMLHttpRequest 2 级规范中。IE 8+是唯一支持超时设定的浏览器
- 2112、Firefox 最早引入了 overrideMimeType() 方法,用于重写 XHR 响应的 MIME 类型。这个方法后来也被纳入了 XMLHttpRequest 2 级规范。因为返回响应的 MIME 类型决定了 XHR 对象如何处理它,所以提供一种方法能够重写服务器返回的 MIME 类型是很有用的
- 2113、微软在 IE8 中引入了 XDR( XDomainRequest )类型。这个对象与 XHR 类似,但能实现安全可靠的跨域通信。XDR 对象的安全机制部分实现了 W3C 的 CORS 规范
- 2114、即使浏览器对 CORS 的支持程度并不都一样,但所有浏览器都支持简单的(非 Preflight 和不带凭据的)请求,因此有必要实现一个跨浏览器的方案。检测 XHR 是否支持 CORS 的最简单方式,就是检查是否存在 withCredentials 属性。再结合检测 XDomainRequest 对象是否存在,就可以兼顾所有浏览器了
- 2115、第一种跨域请求技术是使用 <img> 标签,但该方法只能用于浏览器与服务器间的单向通信
- 2116、JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写,是应用 JSON 的一种新方法,在后来的 Web 服务中非常流行。JSONP 看起来与 JSON 差不多,只不过是被包含在函数调用中的 JSON
- 2117、JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON数据。下面是一个典型的JSONP请求
- 2118、JSONP 是通过动态
<script>
元素(要了解详细信息,请参考第 13 章)来使用的,使用时可以为src 属性指定一个跨域 URL。这里的<script>
元素与 <img> 元素类似,都有能力不受限制地从其他域加载资源。因为 JSONP 是有效的 JavaScript 代码,所以在请求完成后,即在 JSONP 响应加载到页面中以后,就会立即执行 - 2119、Ajax 是一种从页面向服务器请求数据的技术,而 Comet 则是一种服务器向页面推送数据的技术。Comet 能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价
- 2120、SSE(Server-Sent Events,服务器发送事件)是围绕只读 Comet 交互推出的 API 或者模式。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的 MIME类型必须是 text/event-stream ,而且是浏览器中的 JavaScript API 能解析格式输出。SSE 支持短轮询、长轮询和 HTTP 流,而且能在断开连接时自动确定何时重新连接
- 2121、Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。在 JavaScript 中创建了 Web Socket 之后,会有一个 HTTP 请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用 HTTP 升级从 HTTP 协议交换为 WebSocket 协议。也就是说,使用标准的 HTTP 服务器无法实现 Web Sockets,只有支持这种协议的专门服务器才能正常工作
- 2122、使用自定义协议而非 HTTP 协议的好处是,能够在客户端和服务器之间发送非常少量的数据,而不必担心 HTTP 那样字节级的开销。由于传递的数据包很小,因此 Web Sockets非常适合移动应用。毕竟对移动应用而言,带宽和网络延迟都是关键问题。使用自定义协议的缺点在于,制定协议的时间比制定JavaScript API 的时间还要长。Web Sockets曾几度搁浅,就因为不断有人发现这个新协议存在一致性和安全性的问题。Firefox 4 和 Opera 11 都曾默认启用 Web Sockets,但在发布前夕又禁用了,因为又发现了安全隐患。目前支持 Web Sockets 的浏览器有 Firefox 6+、Safari 5+、Chrome 和 iOS 4+版 Safari
- 2123、因为 Web Sockets只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化
- 2124、面对某个具体的用例,在考虑是使用 SSE 还是使用 Web Sockets 时,可以考虑如下几个因素。首先,你是否有自由度建立和维护 Web Sockets服务器?因为 Web Socket 协议不同于 HTTP,所以现有服务器不能用于 Web Socket 通信。SSE 倒是通过常规 HTTP 通信,因此现有服务器就可以满足需求。第二个要考虑的问题是到底需不需要双向通信。如果用例只需读取服务器数据(如比赛成绩),那么 SSE 比较容易实现。如果用例必须双向通信(如聊天室),那么 Web Sockets 显然更好。别忘了,在不能选择 Web Sockets 的情况下,组合 XHR 和 SSE 也是能实现双向通信的
- 2125、同源策略是对 XHR 的一个主要约束,它为通信设置了“相同的域、相同的端口、相同的协议”这一限制。试图访问上述限制之外的资源,都会引发安全错误,除非采用被认可的跨域解决方案。这个解决方案叫做 CORS(Cross-Origin Resource Sharing,跨源资源共享),IE8 通过 XDomainRequest 对象支持CORS,其他浏览器通过 XHR 对象原生支持 CORS。图像 Ping 和 JSONP 是另外两种跨域通信的技术,但不如 CORS 稳妥
- 2126、Comet 是对 Ajax 的进一步扩展,让服务器几乎能够实时地向客户端推送数据。实现 Comet 的手段主要有两个:长轮询和 HTTP 流。所有浏览器都支持长轮询,而只有部分浏览器原生支持 HTTP 流。SSE(Server-Sent Events,服务器发送事件)是一种实现 Comet 交互的浏览器 API,既支持长轮询,也支持HTTP 流
- 2127、Web Sockets是一种与服务器进行全双工、双向通信的信道。与其他方案不同,Web Sockets 不使用HTTP 协议,而使用一种自定义的协议。这种协议专门为快速传输小数据设计。虽然要求使用不同的Web 服务器,但却具有速度上的优势
第二十二章 高级技巧
- 2201、函数绑定可以在特定的 this 环境中以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同时保留代码执行环境
- 2202、一个简单的 bind() 函数接受一个函数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动传递过去
- 2203、ECMAScript 5 为所有函数定义了一个原生的 bind() 方法,进一步简单了操作
485、原生的 bind() 方法与前面介绍的自定义 bind() 方法类似,都是要传入作为 this 值的对象。支持原生 bind() 方法的浏览器有 IE9+、Firefox 4+和 Chrome
- 2204、与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数
- 2205、JavaScript 共享的本质一直是开发人员心头的痛。因为任何对象都可以被在同一环境中运行的代码修改。开发人员很可能会意外地修改别人的代码,甚至更糟糕地,用不兼容的功能重写原生对象。ECMAScript 5致力于解决这个问题,可以让开发人员定义防篡改对象(tamper-proof object)
- 2206、第一行代码已经完整定义 person 对象,但第二行代码仍然能给它添加属性。使用Object.preventExtensions() 方法可以改变这个行为,让你不能再给对象添加属性和方法
- 2207、虽然不能给对象添加新成员,但已有的成员则丝毫不受影响。你仍然还可以修改和删除已有的成员。另外,使用 Object.istExtensible() 方法还可以确定对象是否可以扩展
- 2208、密封对象不可扩展,而且已有成员的 [[Configurable]] 特性将被设置为 false 。这就意味着不能删除属性和方法。要密封对象,可以使用 Object.seal() 方法
- 2209、冻结的对象既不可扩展,又是密封的,而且对象数据属性的 [[Writable]] 特性会被设置为 false 。如果定义 [[Set]] 函数,访问器属性仍然是可写的。ECMAScript 5定义的 Object.freeze() 方法可以用来冻结对象
- 2210、除了主 JavaScript 执行进程外,还有一个需要在进程下一次空闲时执行的代码队列。随着页面在其生命周期中的推移,代码会按照执行顺序添加入队列。例如,当某个按钮被按下时,它的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里执行。当接收到某个 Ajax 响应时,回调函数的代码会被添加到队列。在 JavaScript 中没有任何代码是立刻执行的,但一旦进程空闲则尽快执行
- 2211、定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行。设定一个 150ms 后执行的定时器不代表到了 150ms代码就立刻执行,它表示代码会在 150ms 后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面上看上去好像代码就在精确指定的时间点上执行了。其他情况下,代码可能明显地等待更长时间才执行
- 2212、使用 setInterval() 创建的定时器确保了定时器代码规则地插入队列中。这个方式的问题在于,定时器代码可能在代码再次被添加到队列之前还没有完成执行,结果导致定时器代码连续运行好几次,而之间没有任何停顿。幸好,JavaScript 引擎够聪明,能避免这个问题。当使用 setInterval() 时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中
- 2213、这种重复定时器的规则有两个问题:(1) 某些间隔会被跳过;(2) 多个定时器的代码执行之间的间隔可能会比预期的小
- 2214、运行在浏览器中的 JavaScript 都被分配了一个确定数量的资源。不同于桌面应用往往能够随意控制他们要的内存大小和处理器时间,JavaScript 被严格限制了,以防止恶意的 Web 程序员把用户的计算机搞挂了。其中一个限制是长时间运行脚本的制约,如果代码运行超过特定的时间或者特定语句数量就不让它继续执行。如果代码达到了这个限制,会弹出一个浏览器错误的对话框,告诉用户某个脚本会用过长的时间执行,询问是允许其继续执行还是停止它
- 2215、浏览器中某些计算和处理要比其他的昂贵很多。例如,DOM 操作比起非 DOM 交互需要更多的内存和 CPU 时间。连续尝试进行过多的 DOM相关操作可能会导致浏览器挂起,有时候甚至会崩溃。尤其在 IE 中使用 onresize 事件处理程序的时候容易发生,当调整浏览器大小的时候,该事件会连续触发。在 onresize 事件处理程序内部如果尝试进行 DOM 操作,其高频率的更改可能会让浏览器崩溃。为了绕开这个问题,你可以使用定时器对该函数进行节流
- 2216、只要代码是周期性执行的,都应该使用节流,但是你不能控制请求执行的速率
- 2217、事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术。对象可以发布事件,用来表示在该对象生命周期中某个有趣的时刻到了。然后其他对象可以观察该对象,等待这些有趣的时刻到来并通过运行代码来响应
- 2218、观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者通过订阅这些事件来观察该主体。该模式的一个关键概念是主体并不知道观察者的任何事情,也就是说它可以独自存在并正常运作即使观察者不存在。从另一方面来说,观察者知道主体并能注册事件的回调函数(事件处理程序)。涉及 DOM 上时,DOM 元素便是主体,你的事件处理代码便是观察者
- 2219、拖放是一种非常流行的用户界面模式。它的概念很简单:点击某个对象,并按住鼠标按钮不放,将鼠标移动到另一个区域,然后释放鼠标按钮将对象“放”在这里。拖放功能也流行到了 Web 上,成为了一些更传统的配置界面的一种候选方案
- 2220、JavaScript 中的函数非常强大,因为它们是第一类对象。使用闭包和函数环境切换,还可以有很多使用函数的强大方法。可以创建作用域安全的构造函数,确保在缺少 new 操作符时调用构造函数不会改变错误的环境对象
第二十三章 离线应用与客户端存储
第二十四章 最 佳 实 践
- 2401、变量和函数命名:变量名应为名词如 car 或 person;函数名应该以动词开始,如 getName() 。返回布尔类型值的函数一般以 is 开头,如isEnable(); 变量和函数都应使用合乎逻辑的名字,不要担心长度。长度问题可以通过后处理和压缩(本章后面会讲到)来缓解
- 2402、由于在 JavaScript 中变量是松散类型的,很容易就忘记变量所应包含的数据类型。合适的命名方式可以一定程度上缓解这个问题,但放到所有的情况下看,还不够。有三种表示变量数据类型的方式。第一种方式是初始化;第二种方法是使用匈牙利标记法来指定变量类型;最后一种指定变量类型的方式是使用类型注释
- 2403、只要应用的某个部分过分依赖于另一部分,代码就是耦合过紧,难于维护。典型的问题如:对象直接引用另一个对象,并且当修改其中一个的同时需要修改另外一个。紧密耦合的软件难于维护并且需要经常重写
- 2404、编程实践:尊重对象所有权;避免全局量;避免与 null 进行比较;使用常量
- 2405、性能:注意作用域,避免全局查找,,避免 with 语句;选择正确方法,避免不必要的属性查找,优化循环,展开循环,避免双重解释,原生方法较快, Switch 语句较快,位运算符较快;最小化语句数,多个变量声明,插入迭代值,使用数组和对象字面量;优化DOM交互,最小化现场更新,使用 innerHTML,使用事件委托,注意 HTMLCollection;部署,构建过程,验证,压缩
第二十五章 新兴的API
- 2501、requestAnimationFrame() :是一个着眼于优化 JavaScript 动画的 API,能够在动画运行期间发出信号。通过这种机制,浏览器就能够自动优化屏幕重绘操作。
- 2502、Page Visibility API:让开发人员知道用户什么时候正在看着页面,而什么时候页面是隐藏的。
- 2503、Geolocation API:在得到许可的情况下,可以确定用户所在的位置。在移动 Web 应用中,这个API 非常重要而且常用。
- 2504、File API:可以读取文件内容,用于显示、处理和上传。与 HTML5 的拖放功能结合,很容易就能创造出拖放上传功能。
- 2505、Web Timing:给出了页面加载和渲染过程的很多信息,对性能优化非常有价值。
- 2506、Web Workers:可以运行异步 JavaScript 代码,避免阻塞用户界面。在执行复杂计算和数据处理的时候,这个 API 非常有用;要不然,这些任务轻则会占用很长时间,重则会导致用户无法与页面交互。
附录 A
- 常量
- 块级作用域及其他作用域
- 剩余参数与分布参数
- 默认参数值
- 生成器
- 迭代器
- 数组领悟
- 解构赋值
- 代理对象
- 代理函数
- 映射与集合
- WeakMap
- StructType
- ArrayType
- 类,私有成员
- getter 和 setter
- 继承
- 模块
附录 B
- 选择使用
- 变量
- 对象
- 函数
- eval()
- eval 与 arguments
- 抑制 this
- 其他变化
附录 C
- JavaScript 库
附录 D
- JavaScript工具
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。