继续阅读,这里是客户端JavaScript实现的部分

JavaScript权威指南

Web浏览器中的JavaScript

  • Location对象的新发现

    1
    2
    3
    location == location.href // true,location 对象调用了 toString() 方法
    location = 'www.example.com' // 相当于给 location.href 赋值
    window.location === document.location // true
  • <script> 标签如果有 src 属性,则 <script> 标签中的任何内容均会被忽略

  • <script> 标签中如果包含不被浏览器识别的 type 属性,浏览器会尝试解析但不执行/显示,利用这个可以做成 HTML模板 (只限内联),如 <script type="yhsd-template">...模板内容...</script>;但如果同时又指定了 src 属性,该标签会被忽略

window对象

  • setTimeout(func, 0) 中,函数 func 不会立刻执行,而是等待前面事件处理程序都运行完再“立即”执行
  • 一个有趣的历史遗留问题是,当元素的 id (或特殊元素的 name)不是 window 对象的一个属性时,该元素会被隐式的成为全局的一个属性。实践中尽量避免使用这种方式,HTML5 标准中已废弃
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <button id="btn">我会被隐式成为全局属性</button>
    <button id="alert">我被alert方法覆盖了!!!</button>
    <button id="user">我被自定义全局变量方法覆盖了!!!</button>
    <br>
    <img class="foo" name="foo" src="example2.png">
    <img class="foo" name="foo" src="example3.png">
    <script>
    window.btn === document.getElementById('btn') // true
    window.alert === document.getElementById('alert') // false,被 window.alert 方法覆盖
    //
    var user = 'user defined'
    window.user === document.getElementById('user') // false,被自定义全局变量覆盖了
    //
    window.foo === document.getElementsByClassName('foo') // false 前者为 HTMLCollection 对象,后者为NodeList对象
    </script>

脚本化文档

  • HTMLCollection 和 NodeList 对象是动态的,实时反应 DOM 中的变化,因此在实际应用中可能需要保存获取时的静态副本以避免后续变动造成影响
  • HTMLCollection 和 NodeList 对象具有细微的区别,前者是标准DOM的 Core 接口,后者为 HTML 独有并多了一个 namedItem 方法;HTMLCollection 是元素集合而 NodeList 是节点集合(即可以包含元素,也可以包含文本节点)
  • 标准显示的文档中,getElementsByClassName() 方法区分大小写(怪异模式则不区分大小写)
  • IE8不支持 getElementsByClassName() 方法,但却支持 querySelectorAll() 方法
  • 通过 querySelectorAll() 获取的 NodeList 对象不是实时动态的,而是获取时的静止快照。querySelector() 只选中第一个匹配的元素。

    在Element调用 querySelector 方法,选择器仍然搜索整个文档,但会过滤出基于该 Element 的后代元素返回,这意味着在这种情况下相对于 getElementBy*方法 会消耗更多的性能

  • 对于 <p>This is a <i>simple</i>document</p> 而言,<p> 标签中的内容是什么?

    • innerHTML —— This is a <i>simple</i>document
    • outerHTML —— <p>This is a <i>simple</i>document</p>
    • innerText —— This is a simple document
  • 元素、滚动条、窗口的大小位置获取及设置的理解(结合图示)
  • onsubmit 事件处理程序中返回 false 可取消提交,该事件只能通过“提交”按钮触发,直接用JS调用 submit() 方法无效(onreset 同理)
  • 建议不用 <a> 标签模拟非链接的按钮,以更加语义化(当脚本失效时用链接代替按钮的功能是一种优雅降级,脚本失效仍可点开新页面进入下一步)
  • 单选/复选按钮中使用 change 事件代替 click
  • <input type="file">value 是只读的,防止恶意JS上传
  • 通过设置标签的 contenteditable 属性创建可编辑区域是富文本编辑器的常用手段,其中浏览器支持多种 API,但这些 API 的兼容可能需要考虑,建议使用富文本编辑器插件。

脚本化CSS

  • 元素的style属性的值是一个 CSSStyleDeclaration 对象,而非字符串,而其所有属性的值都是字符串(必须带单位,如’20px’);该对象读取和改变的均是 HTML/JS 显示声明的内联样式,因此外联样式表的样式无法被读取。
  • 计算样式也是得到一个 CSSStyleDeclaration 对象,使用 window.getComputedStyle(element, null)
    • 计算样式是只读的
    • 其属性的值是绝对值,相对值会转化成绝对值
    • 不计算 margin 这种复合属性,而是 marginLeft 这种基础属性
    • 未定义 cssText 属性
    • 不支持 IE8 及以下版本(IE 中类似的方法为 currentStyle)
  • 通过 document.styleSheets 可获得只读的样式列表,包括内联和外联样式

事件处理

  • focusblur 事件不会冒泡
  • 如使用 beforeunload 事件可以询问用户是否离开当前页面
  • addEventListener() 方法的第三个参数通常省略(省略false即为冒泡模式),相同参数只能注册一次
  • IE8使用attachEvent(),只支持事件冒泡(因此没有第三个参数),带 on 前缀,可多次注册多次调用
  • 通过设置属性注册 IE8 的事件对象时通过 window.event 传递而非标准的参数

    1
    2
    3
    4
    e.onclick = function (event) {
    event = event || window.event; // IE8中通过window.event传递event
    }
    // 而在attachEvent则两种方式均可
  • 事件处理程序的运行环境如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 通过设置属性注册,会被转换为能存取全局变量的顶级函数,但由于历史原因,也能使用局部变量
    e.onclick = function (event) {
    this === event // true, this 指向事件目标
    }
    // 通过事件添加器注册
    e.addEventListener('click', function (event) {
    this === event // true, this 指向事件目标
    }, false)
    //
    e.attachEvent('click', function (event) {
    this === event // false, this 指向全局对象 window
    })
  • 尽量避免使用 HTML 属性来绑定事件处理程序,因为其隐式改过的作用域会导致许多问题

  • 通过 HTML 属性绑定的事件处理程序返回 false 可阻止其默认行为,而通过 addEventListener()attachEvent() 方式则可通过调用 preventDefault() 或者设置其 returnValue 属性实现
  • 多个事件处理程序作用于同一个事件时,通过 HTML 属性绑定的事件处理程会优先调用(类似内联样式),addEventListener() 则按注册顺序调用
  • 文档元素的 load 事件会冒泡到 document 对象并停止(不会冒泡到 window 对象),只有整个文档都加载完毕才会出发 windowload 事件
  • 事件传播的三个阶段:事件捕获,目标事件处理程序,事件冒泡(DOM Lv3中标准化)
  • addEventListener() 调用 stopPropagation(),或 attachEvent() 设置 cancelBubble 属性为 true,均可阻止事件的传播(阻止冒泡)
  • window 对象的 load 事件触发需要文档和全部图片等资源加载完毕后才触发,而 DOMContentLoaded 事件则在 DOM 结构解析完毕且延迟脚本执行完毕即触发(在具备很多图片和异步脚本时比 load 事件更快完成,类似 jQuery 的 $(document).ready() 方法)
  • 除了mouseentermouseleave 外的鼠标事件均会冒泡

脚本化HTTP

  • 常见的实现(均基于GET):
    • 方法1:设置一个 <img> 元素的src属性,把信息(如当前地址)作为图片 URL 的查询字符串部分,服务器会返回一个信标图片作为请求结果(通常是1×1像素的透明图片),该方法是单向的,但不受同源限制,一般用来跟踪流量
    • 方法2:使用 <iframe> (通常对用户也不可见)代替 <img>,服务器返回是包含响应内容的 HTML 在 iframe 中显示,脚本再遍历得到目的信息,该方法受限于同源策略
    • 方法2:设置 <script> 作为容器,该方法兼具方法1和方法2的优点(双向交互,不受同源限制),常见主流实现如JSONP
  • GET 请求适用于 URL 完全制定请求资源,对服务器无任何副作用,且其响应可缓存的情况
  • xhr.open('GET', url, false),第三个参数显示传入 false,则该请求为同步阻塞的,一般避免使用

客户端存储

  • localStoragesessionStorage 均代表同一个 Storage 对象(一个持久化关联数组),数组的使用字符串索引和字符串形式的值;两者的区别在于存储时间及访问权限
    • localStorage 的存储期限是永久的(除非刻意删除),而 sessionStorage 则在标签(会话级别)关闭后即失效
    • localStorage 可被同源文档读写(不同标签页间共享),而 sessionStorage 不禁限制同源还限制不同标签页不能共享
  • Storage 数据发生改变时会触发存储事件(onstorage)
  • IE8 以上版本支持 Storage,而 IE6/IE7 可用类似的 userData 实现
  • 同源一般说明:协议、主机名、端口均相同
  • 要判断浏览器的 cookie 是否启用的兼容方法是快速写入 / 读取测试数据
  • cookie 的可读性与创建它的页面有关,当前页面同目录及其子目录可见,而对其他页面不可见(可通过设置参数设置其目录路径)
  • cookie 在大部分浏览器中有大小限制,单个cookie 限制为 4kb
  • 离线存储前需要设置 manifest (MIME类型:text/cache-manifest)清单:

    1
    2
    3
    4
    5
    6
    <html manifest="myapp.appcache">...</html>
    <!-- 以下是上述清单文档的内容,更新版本号可让浏览器重新获取新资源以替换过时缓存 -->
    # Myapp version 1
    myapp.html
    myapp.css
    myapp.png
  • navigator.onLine 属性可以判断当前应用是否在线

多媒体和图形编程

  • SVG 是一种描述图形的 XML 语法,IE9 及以上浏览器支持;
  • IE9 及以上浏览器支持 <canvas>

HTML5 API

  • 地理位置 API 通常会弹窗提示用户授权使用位置信息
  • 利用 location.hash 和对应的 hashchange 事件可以实现IE8中的单页应用历史管理
  • 利用GTML5新增的 history.pushStatehistory.replaceState 及对应事件,可灵活管理 SPA 的历史状态
  • IE8 支持 window.postMessage() 方法进行窗口间信息传递