JS红宝书·读书笔记 -- 下篇

JS红宝书·读书笔记 -- 下篇_第1张图片
JavaScript 高级程序设计

个人博客:https://yeaseonzhang.github.io

花了半个多月的时间,终于又把“JS红宝书”又撸了一遍。

第一次读“JS红宝书”还是2015年初学JS的时候,那时候只是把语法部分读了一遍,还有一些浏览器相关知识做了下了解,大概也就读了半本的样子,
就开始了用JS进行开发了,在成长的道路上遇见了JQuery,当时真的是感觉到JQuery太友好了,慢慢放下了原生开发。

现在呢,更多的时候是在用框架进行开发,越来越觉得自己的JS基础很缺乏,然后就开启了“JS红宝书”二刷之路。

下面就把书中自己觉得重要的、没有掌握的知识整理出来。因为我觉得还是会三刷“JS红宝书”,希望把这本700多页的书越读越薄,勉励。

章节

  • 事件
  • 表单脚本
  • HTML5脚本编程
  • 错误处理与调试
  • JSON
  • Ajax 与 Comet
  • 高级技巧
  • 离线应用与客户端存储
  • 新型的API

事件


事件流

事件冒泡

IE的事件流叫做事件冒泡,即事件开始时由最具体的元素接受,然后逐级向上传播到较为不具体的节点。

事件捕获

Netscape 团队提出的事件流叫做事件捕获,事件捕获的用意在于在事件到达预定目标之前捕获它。

DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段

事件处理程序

DOM0 级事件处理程序

每个元素(包括windowdocument)都有自己的事件处理程序,这些属性通常全部小写。

var btn = document.getElementById('myBtn');
btn.onclick = function () {
    console.log('clicked');
}

DOM 0级方法指定的事件处理程序被认为是元素的方法,因此,这个时候的事件处理程序是在元素的作用域中运行,也就是说程序中的this可以引用当前元素。

var btn = document.getElementById('myBtn');
btn.onclick = function () {
    console.log(this.id);  // 'myBtn'
}

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

DOM2 级事件处理程序

  • addEventListener()
  • removeEventListener()

定义了两个方法用于处理指定和删除事件处理程序的操作。所有的DOM节点中都包含这两个方法,接受三个参数:事件名事件处理程序布尔值。最后这个布尔值如果是true,表示在捕获阶段调用事件处理程序;false表示在冒泡阶段调用事件处理程序,默认是false

通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除。如果通过addEventListener()添加的匿名函数将无法移除。

btn.addEventListener('click', function () {  //匿名函数
    ...
})

:大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段(false),这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。

IE事件处理程序

  • attachEvent()
  • detachEvent()

这两个方法接受两个参数:事件名(带on)和事件处理函数。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
    alert("Clicked");
});

:在IE 中使用attachEvent()与使用DOM0 级方法的主要区别在于事件处理程序的作用域。

  • DOM0 级作用域是其所属元素
  • attachEvent()方法的作用域是全局(this === window
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
    alert("Clicked");
});
btn.attachEvent("onclick", function(){
    alert("Hello world!");
});

:与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是"Hello world!",然后才是"Clicked"。

事件对象

在触发DOM上的某个事件时,会产生一个事件对象event

DOM中的事件对象

event对象成员

| 属性/方法 | 类型 | 读/写 | 说明 |
| : - : | : -- : | : -- : | : -- : | : -- : |
| bubbles | Boolean | 只读 | 表明事件是否冒泡 |
| cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
| currentTarget | Element | 只读 | 其事件处理程序当前正在处理事件的那个元素 |
| defaultPrevented | Boolean | 只读 | 为true表示已经调用preventDefault() |
| detail | Integer | 只读 | 与事件相关的细节信息 |
| eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1 捕获,2 处于目标,3 冒泡 |
| preventDefault() | Function | 只读 | 取消事件的默认行为。如果cancelabletrue,则可以使用这个方法 |
| stopImmediatePropagation() | Function | 只读 | 取消事件的进一步冒泡或捕获,同时阻止任何事件处理程序被调用 |
| stopPropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。如果bubblestrue,则可以使用这个方法 |
| target | Element | 只读 | 事件的目标 |
| trusted | Boolean | 只读 | 为true表示事件是浏览器生成,false是开发人员创建 |
| type | String | 只读 | 被触发的事件类型 |
| view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的window对象 |

在事件处理程序内部,对象this 始终等于currentTarget 的值,而target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则thiscurrentTargettarget 包含相同的值。

document.body.onclick = function(event){
    alert(event.currentTarget === document.body); //true
    alert(this === document.body); //true
    alert(event.target === document.getElementById("myBtn")); //true
};

调用event方法

var link = document.getElementById("myLink");
link.onclick = function(event){
    event.preventDefault();
};

跨浏览器的事件对象

var EventUtil = {
    addHandler: function(element, type, handler){
        //省略的代码
    },
    getEvent: function(event){
        return event ? event : window.event;
    },
    getTarget: function(event){
        return event.target || event.srcElement;
    },
    preventDefault: function(event){
        if (event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler){
        //省略的代码
    },
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

事件类型

UI 事件

  • load事件
  • unload事件
  • resize事件
  • scroll事件

焦点事件

  • blur事件:失去焦点
  • focus事件:获得焦点

鼠标与滚动事件

  • click事件
  • dbclick事件
  • mousedown事件:按下鼠标
  • mouseenter事件:光标移入
  • mouseleave事件:光标移出
  • mousemove事件:鼠标在元素内部移动重复触发
  • mouseout事件:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素
  • mouseover事件:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发
  • mouseup事件:释放鼠标按钮时触发

页面上的所有元素都支持鼠标事件。除了mouseentermouseleave,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。

只有在同一个元素上相继触发mousedownmouseup 事件,才会触发click 事件;如果mousedownmouseup 中的一个被取消,就不会触发click 事件。

触摸设备

iOS和Android设备的相关事件:

  • 不支持dbclick事件。双击浏览器窗口会放大画面
  • 轻击可单击元素会触发mousemove事件。。如果此操作会导致内容变化,将不再有其他事件发生;如果屏幕没有因此变化,那么会依次发生mousedownmouseupclick 事件。轻击不可单击的元素不会触发任何事件。可单击的元素是指那些单击可产生默认操作的元素(如链接),或者那些已经被指定了onclick 事件处理程序的元素。
  • mousemove事件也会触发mouseovermouseout事件
  • 两个手指放在屏幕上且页面随手指移动而滚动时会触发mousewheelscroll事件。

HTML5事件

  • contextmenu事件
  • beforeunload事件
  • DOMContentLoaded事件
  • readystatechange事件
    • uninitialized未初始化
    • loading
    • loaded
    • interactive:可以操作对象,但还没有完全加载
    • complete
  • hashchange事件

设备事件

  • orientationchange事件:横竖屏,有三个值: -90 ,0, 90

触摸与手势事件

  • 触摸事件
    • touchstart
    • touchmove
    • touchend
    • touchcancel
  • 手势事件
    • gesturestart
    • gesturechange
    • gestureend

内存和性能

事件委托

例如在

    为添加一个click事件,所有
  • 子元素点击事件都会冒泡到
      上。

      表单脚本


      表单基础知识

      提交表单

      
      

      重置表单

      
      

      表单字段

      每个表单都有elements属性,该属性是表单中所有表单元素的集合。

      var form = document.getElementById("form1");
      //取得表单中的第一个字段
      var field1 = form.elements[0];
      //取得名为"textbox1"的字段
      var field2 = form.elements["textbox1"];
      //取得表单中包含的字段的数量
      var fieldCount = form.elements.length;
      

      文本框脚本

      过滤输入

      屏蔽特定的字符,需要检测keypress事件对应的字符编码。

      EventUtil.addHandler(textbox, 'keypress', function (event) {
          event = EventUtil.getEvent(event);
          var target = EventUtil.getTarget(event);
          var charCode = EventUtil.getCharCode(event);
      
          if (!/\d/.test(String.fromCharCode(charCode))) {
              EventUtil.preventDefault(event);
          }
      })
      

      HTML5约束验证API

      输入模式

      HTML5为文本字段新增了pattern属性。

      
      
      检测有效性

      使用checkValidity()方法可以检测表单中的某个字段是否有效。是否有效的判断依据是一些的约束条件。

      if (document.forms[0].elements[0].checkValidity()){
          //字段有效,继续
      } else {
          //字段无效
      }
      

      也可以检测整个表单是否有效

      if(document.forms[0].checkValidity()){
          //表单有效,继续
      } else {
          //表单无效
      }
      
      禁用验证

      HTML5 脚本编程


      跨文档消息传递

      跨文档消息传送(cross-document messaging)简称XDM。其核心方法是postMessage()方法。

      postMessage()方法接受两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。

      // 注意:所有支持XDM的浏览器也支持iframe的`contentWindow`属性
      var iframeWindow = document.getElementById('myframe').contentWindow;
      iframeWindow.postMessage('A secret', 'https://yeasoenzhang.github.io');
      

      尝试向内嵌框架中发送一条消息,并指定框架中的文档必须来源于https://yeasonzhang.github.io域。

      接收到XDM消息时,会触发window对象的message事件,这个事件是以异步形式触发。
      传递的onmessage处理程序的事件对象包含三个重要信息:

      • data:作为postMessage()第一个参数传入的字符串数据
      • origin:发送消息的文档所在的域。
      • source:发送消息的文档的window对象的代理。
      EventUtil.addHandler(window, "message", function(event){
          //确保发送消息的域是已知的域
          if (event.origin == "https://yeasonzhang.github.io"){
              //处理接收到的数据
              processMessage(event.data);
              //可选:向来源窗口发送回执
              event.source.postMessage("Received!", "http://p2p.wrox.com");
          }
      });
      

      XDM 还有一些怪异之处。首先,postMessage()的第一个参数最早是作为“永远都是字符串”来实现的。但后来这个参数的定义改了,改成允许传入任何数据结构。可是,并非所有浏览器都实现了这一变化。为保险起见,使用postMessage()时,最好还是只传字符串。如果你想传入结构化的数据,最佳选择是先在要传入的数据上调用JSON.stringify(),通过postMessage()传入得到的字符串,然后再在onmessage 事件处理程序中调用JSON.parse()

      原生拖放

      拖放事件

      拖动某个元素时,将依次触发的事件:

      • dragstart
      • drag
      • dragend

      当某个元素被拖动到一个有效的放置目标时,会依次触发下列事件:

      • dragenter
      • dragover
      • dragleave(离开)或drag(放进去了)

      dataTransfer对象

      dataTransfer对象,它是事件对象的一个属性,用于被拖动元素向放置目标传递字符串格式的数据。该对象有两个主要方法:

      • getData()
      • setData()
      //设置和接收文本数据
      event.dataTransfer.setData("text", "some text");
      var text = event.dataTransfer.getData("text");
      
      //设置和接收URL
      event.dataTransfer.setData("URL", "http://www.wrox.com/");
      var url = event.dataTransfer.getData("URL");
      

      不过,保存在dataTransfer对象中的数据只能在drap事件处理程序中读取。如果在ondrop 处理程序中没有读到数据,那就是dataTransfer 对象已经被销毁,数据也丢失了。

      drapEffect 与 effectAllowed

      dateTransfer对象有两个属性:

      • dropEffect
      • effectAllowed

      dropEffect,属性可以知道被拖动的元素能够执行那种放置行为。

      • none:不能放在这里
      • move:应该把拖放的元素移动到放置目标
      • copy:应该把拖动的元素复制到放置目标
      • link:表示放置目标会打开拖动的元素

      要使用dropEffect属性,必须在ondragenter事件处理程序中针对放置目标来设置。

      effectAllowed属性表示允许拖动元素的哪种dropEffect

      • uninitialized:没有给被拖动的元素放置任何放置行为
      • none:被拖动的元素不能有任何行为
      • copy:只允许值为copydropEffect
      • link:只允许值为linkdropEffect
      • move:只允许值为movedropEffect
      • copyLink:允许值为copylinkdropEffect
      • copyMove:允许值为copymovedropEffect
      • linkMove:允许值为linkmovedropEffect
      • all: 允许任意dropEffect

      必须在ondragstart 事件处理程序中设置effectAllowed 属性。

      可拖动

      HTML5为所有元素规定了draggable属性,表示元素是否可以拖动。只有图像和链接的draggable默认是true

      
      ![](smile.gif)
      
      
      ...

      其他成员

      HTML5规定了dateTransfer对象还应该包含下列方法和属性。

      • addElement(element)
      • clearData(format)
      • setDragImage(element, x, y)
      • type

      错误处理与调试


      错误处理

      try-catch 语句

      try {
          // 可能出错的代码
      } catch (err) {
          // 处理发生的错误
      }
      
      finally子句

      只要代码中包含finially子句,无论try还是catch语句中的return语句都将被忽略。

      错误类型
      • Error
      • EvalError
      • RangeError
      • ReferenceError
      • SyntaxError
      • TypeError
      • URIError
      try {
          someFunction();
      } catch (error) {
          if (error instanceof TypeError) {
              //...
          } else {
              //
          }
      }
      

      抛出错误

      try-catch 语句相配的还有一个throw 操作符,用于随时抛出自定义错误。抛出错误时,必须要给throw 操作符指定一个值,这个值是什么类型,没有要求。

      throw 12345;
      throw "Hello world!";
      throw true;
      throw { name: "JavaScript"};
      

      遇到throw操作符时,代码会立即停止执行。只有当try-catch语句捕获到被抛出值,代码才会继续执行

      自定义错误类型

      可以利用原型链通过继承Error创建自定义错误类型。需要为新创建的错误类型指定namemessage属性

      function CustomError (message) {
          this.name = 'CustomError';
          this.message = message;
      }
      
      CustomError.prototype = new Error();
      
      throw new CustomError('Error msg');
      

      Error事件

      任何没有通过try-catch处理的错误都会触发window对象的error事件。

      在任何Web浏览器中,onerror事件处理程序都不会创建event对象,但它可以接受三个参数:错误消息、错误所在的URL和行号。

      要指定onerror 事件处理程序,必须使用如下所示的DOM0 级技术,它没有遵循“DOM2 级事件”的标准格式(addEventListener)。

      window.onerror = function(message, url, line){
          alert(message);
      };
      

      只要发生错误,无论是不是浏览器生成的,都会触发error事件,然后让浏览器的默认机制发挥作用,这时候我们需要阻止浏览器的默认行为(return false)。

      window.onerror = function (message, url, line) {
          console.log(message);
          retrun false;
      }
      

      常见的错误类型

      • 类型转换错误
      • 数据类型错误
      • 通信错误

      在数据检测的时候,基本类型的值应该使用typeof来检测,对象的值应该使用instanceof

      JSON


      解析与序列化

      JSON对象

      JSON对象有两个方法:stringifyparse()

      var book = {
          title: "Professional JavaScript",
          authors: [
              "Nicholas C. Zakas"
          ],
          edition: 3,
          year: 2011
      };
      var jsonText = JSON.stringify(book);
      

      以上就把Javascript对象序列化为一个JSON字符串(没有空格和缩进)

      {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011}
      

      如果传给JSON.parse()的字符串不是有效的JSON,会抛出错误。

      序列化选项

      JSON.stringify()除了要序列化的JS对象外,还可以接受两个参数,一个是过滤器(数组或函数),第二个参数是一个选项,表示是都在JSON字符串中保留缩进。

      过滤结果
      var book = {
          "title": "Professional JavaScript",
          "authors": [
              "Nicholas C. Zakas"
          ],
          edition: 3,
          year: 2011
      };
      var jsonText = JSON.stringify(book, ["title", "edition"]);
      

      第二个参数中包含两个字符串"title", "edition",所以只会返回对应的属性

      {"title":"Professional JavaScript","edition":3}
      

      过滤器为函数

      var book = {
          "title": "Professional JavaScript",
          "authors": [
              "Nicholas C. Zakas"
          ],
          edition: 3,
          year: 2011
      };
      var jsonText = JSON.stringify(book, function(key, value){
          switch(key){
              case "authors":
                  return value.join(",")
              case "year":
                  return 5000;
              case "edition":
                  return undefined;
              default:
                  return value;
          }
      });
      

      :返回undefined删除该属性,上例的edition属性就会被删除。

      字符串缩进

      JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。可以是数字,表示缩进的空格数;也可以是字符串,将该字符串作为缩进的表示。

      toJSON()方法

      解析选项

      JSON.parse()方法也可以接受第二参数,该参数是一个函数(被称为还原函数),传入函数的参数均为key, value

      如果还原函数返回undefined,则表示要从结果中删除响应的键。

      Ajax与Comet


      XMLHttpRequest 对象

      XHR的用法

      • open('method', 'url', bool):第三个参数表示是否异步发送
      • send():接受一个参数作为请求主体发送的数据,如果不需要则传入null

      XHR对象的属性

      • responseText:作为相应主体被返回的文本
      • responseXML:如果相应的内容类型是"text/xml""application/xml",这个属性中将包含这响应数据的XML DOM文档
      • status:响应的HTTP状态
      • statusText:HTTP状态的说明

      同步请求

      xhr.open("get", "example.txt", false);
      xhr.send(null);
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
          alert(xhr.responseText);
      } else {
          alert("Request was unsuccessful: " + xhr.status);
      }
      
      
      • readyState:表示请求/响应过程的阶段
        • 0:未初始化,尚未调用open()方法
        • 1:启动,调用了open()方法,尚未调用send()方法
        • 2:发送,调用了send()方法,尚未接收到响应。
        • 3:接收,接收到部分响应数据
        • 4:完成,已经接收到全部响应数据
      var xhr = createXHR();
      xhr.onreadystatechange = function(){
          if (xhr.readyState == 4){
              if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                  alert(xhr.responseText);
              } else {
                  alert("Request was unsuccessful: " + xhr.status);
              }
          }
      };
      xhr.open("get", "example.txt", true);
      xhr.send(null);
      
      • abort():在接收到响应之前通过该方法取消异步请求。
        建议调用这个方法之后,对XHR对象进行解引用操作。

      HTTP 头部信息

      默认情况下,在发送XHR请求的同时,还会发送下列头部信息:

      • Accept:浏览器能够处理的内容类型
      • Accept-Charset:浏览器能够显示的字符集
      • Accept-Encoding:浏览器能够处理的压缩编码
      • Accept-Language:浏览器当前设置的语言
      • Connection:浏览器与服务器之间连接的类型
      • Cookie: 当前页面的 Cookie
      • Host:发出请求的页面所在的域
      • Referer:发出请求的页面的URI
      • User-Agent:浏览器的用户代理

      自定义请求头部信息,使用setRequestHeader()方法,该方法接受两个参数:头部字段的名称和头部字段的值。

      要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用serRequestHeader()

      var xhr = createXHR();
      xhr.onreadystatechange = function(){
          // ...
      };
      xhr.open("get", "example.php", true);
      xhr.setRequestHeader("MyHeader", "MyValue");
      xhr.send(null);
      

      建议使用自定义的头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的响应。有的浏览器允许开发人员重写默认的头部信息,但有的浏览器则不允许这样做。

      调用XHR对象的getResponseHeader()方法,接受一个参数:头部字段名称。就能取得相应的响应头部信息。
      调用getAllResponseHeaders()方法可以取得包含所有头部信息的字符串。

      GET请求

      使用GET请求经常会发生一个错误,就是查询字符串的格式有问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码,然后才能放到URL的末尾。

      function addURLParam(url, name, value) {
          url += (url.indexOf("?") == -1 ? "?" : "&");
          url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
          return url;
      }
      
      var url = "example.php";
      //添加参数
      url = addURLParam(url, "name", "Nicholas");
      url = addURLParam(url, "book", "Professional JavaScript");
      //初始化请求
      xhr.open("get", url, false);
      

      POST请求

      如果我们希望用XHR模仿表单提交,需要将Content-Type头部信息设置为application/x-www-form-urlencoded(表单提交的内容类型)

      function submitData(){
          var xhr = createXHR();
          xhr.onreadystatechange = function(){
              if (xhr.readyState == 4){
                  if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                      alert(xhr.responseText);
                  } else {
                      alert("Request was unsuccessful: " + xhr.status);
                  }
              }
          };
          xhr.open("post", "postexample.php", true);
          xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          var form = document.getElementById("user-info");
          xhr.send(serialize(form));
      }
      

      XMLHttpRequest 2 级

      FormData

      FormData为序列化表单以及创建于表单格式相同的数据提供了便利。

      var data = new FormData();
      data.append('name', 'Yeaseon');
      

      append方法可以将表单的字段和值,传入FormData对象中。也可以预先填入表单中的字段:

      var data = new FormData(document.form[0]);
      

      FormData的方便就在于不必手动修改XHR对象的请求头部。

      超时设定

      XHR对象添加了一个timeout属性,表示请求在等待多少毫秒之后终止。如果规定时间内浏览器没有收到响应,就会触发timeout事件,进而调用ontimeout事件处理程序。

      var xhr = createXHR();
      xhr.onreadystatechange = function(){
          // ...
      };
      xhr.open("get", "timeout.php", true);
      xhr.timeout = 1000; //将超时设置为1 秒钟
      xhr.ontimeout = function(){
          alert("Request did not return in a second.");
      };
      xhr.send(null);
      

      超时之后请求终止,但是此时的readyState可能已经变为了4,就意味着会调用onreadystatechange事件。

      可是,如果在超时终止请求之后再访问status 属性,就会导致错误。为避免浏览器报告错误,可以将检查status 属性的语句封装在一个try-catch语句当中。

      overrideMimeType()方法

      用于重写XHR响应的MIME类型。因为返回响应的MIME 类型决定了XHR 对象如何处理它,所以提供一种方法能够重写服务器返回的MIME 类型是很有用的。

      var xhr = createXHR();
      xhr.open("get", "text.php", true);
      xhr.overrideMimeType("text/xml");
      xhr.send(null);
      

      进度事件

      有以下6个进度事件:

      • loadstart:在接收到响应数据的第一个字节触发
      • progress:在接收响应期间持续不断地触发
      • error:在请求发生错误时触发
      • abort:在因为调用abort()方法而终止连接时触发
      • load:在接收到完整的响应数据时触发
      • loadend:在通信完成或者触发errorabort,或load事件后触发

      progress事件
      onprogress事件处理程序会接收到一个event对象,target属性指向XHR对象,包含着三个额外的属性:

      • lengthComputable:表示进度信息是否可用的布尔值
      • position:表示已经接受的字节数
      • totalSize:表示根据Content-Length响应头部确定的预期字节数。

      跨资源共享

      IE对CORS的实现

      微软在IE8中引入了XDR类型,类似与XHR对象,两者的不同之处:

      • cookie不会随请求发送,也不会随响应返回
      • 只能设置请求头部信息中的Content-Type字段
      • 不能访问响应头部信息
      • 只支持GETPOST请求

      请求返回之后,就会触发load事件,响应数据也会保存在responseText属性中:

      var xdr = new XDomainRequest();
      xdr.onload = function () {
          console.log(xdr.responseText);
      };
      xdr.onerror = function(){
          alert("An error occurred.");
      };
      xdr.open('get', 'http://..../xxx/');
      xdr.send(null);
      

      在请求返回之前可以调用abort()方法终止请求。

      xdr.abort();
      

      XDR对象也支持timeout属性以及ontimeout事件处理程序

      var xdr = new XDomainRequest();
      xdr.onload = function(){
          alert(xdr.responseText);
      };
      xdr.onerror = function(){
          alert("An error occurred.");
      };
      xdr.timeout = 1000;
      xdr.ontimeout = function(){
          alert("Request took too long.");
      };
      xdr.open("get", "http://www.somewhere-else.com/page/");
      xdr.send(null);
      

      为了支持POST请求,XDR对象提供了contentType属性,用来表示发送数据的格式。

      var xdr = new XDomainRequest();
      xdr.onload = function () {
          //
      }
      xdr.onerror = function () {
          //
      }
      xdr.open('post', 'http://www.somewhere-else.com/page/');
      xdr.contentType = 'application/x-www-form-urlencoded';
      xdr.send('name1=value1&name2=value2');
      

      其他浏览器对CORS的实现

      与IE中的XDR对象不同,通过跨域XHR对象可以访问statusstatusText属性,并且支持同步请求。同时也有一些限制:

      • 不能使用setRequestHeader()设置自定义头部
      • 不能发送和接收cookie
      • 调用getAllResponseHeaders()方法总会返回空字符串
      var xhr = createXHR();
      xhr.onreadystatechange = function(){
          if (xhr.readyState == 4){
              if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                  alert(xhr.responseText);
              } else {
                  alert("Request was unsuccessful: " + xhr.status);
              }
          }
      };
      xhr.open("get", "http://www.somewhere-else.com/page/", true);
      xhr.send(null);
      

      其他跨域技术

      图像Ping

      var img = new Image();
      img.onload = img.onerror = function(){
          alert("Done!");
      };
      img.src = "http://www.example.com/test?name=Nicholas";
      

      JSONP

      JSONPJSON with padding的简写。JSONP只不过时被包含在函数调用中的JSON

      callback({"name": "Yeaseon"});
      

      JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是请求中指定的。下面是一个经典的JSONP请求

      http://freegeoip.net/json/?callback=handleResponse
      

      这里指定的回调函数的名字叫做handleResponse

      JSONP是通过动态

你可能感兴趣的:(JS红宝书·读书笔记 -- 下篇)