js高级程序设计第七部分

js高级程序设计:canvas、错误调试、json、ajax、其它

使用 Canvas 绘图

基本用法

  1. 要使用元素,必须先设置其 width 和 height 属性,指定可以绘图的区域大小。
A drawing of something.
  1. 要在这块画布(canvas)上绘图,需要取得绘图上下文。而取得绘图上下文对象的引用,需要调用getContext()方法并传入上下文的名字,注意要先检测getContext()方法是否存在
  2. 使用 toDataURL()方法,可以导出在元素上绘制的图像。这个方法接受一个参数,即图像的 MIME 类型格式,而且适合用于创建图像的任何上下文
    后面的内容在首页不显示,请点击下方的展开全文或者
//取得画布中的一幅 PNG 格式的图像
var drawing = document.getElementById("drawing"); 
//确定浏览器支持元素
if (drawing.getContext){ 
 //取得图像的数据 URI 
 var imgURI = drawing.toDataURL("image/png"); 
 //显示图像
 var image = document.createElement("img"); 
 image.src = imgURI; 
 document.body.appendChild(image); 
}

2D上下文,可以绘制简单2D图形

2D 上下文的坐标开始于元素的左上角,原点坐标是(0,0)。所有坐标值都基于这个原点计算,x 值越大表示越靠右,y 值越大表示越靠下。默认情况下,width 和 height 表示水平和垂直两个方向上可用的像素数目。

填充与描边

  1. 填充,就是用指定的样式(颜色、渐变或图像)填充图形;描边,就是只在图形的边缘画线,这两个操作的结果取决于于两个属性:fillStyle 和 strokeStyle。这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值都是"#000000"。
var drawing = document.getElementById("drawing"); 
//确定浏览器支持元素
if (drawing.getContext){ 
 var context = drawing.getContext("2d"); 
 context.strokeStyle = "red"; 
 context.fillStyle = "#0000ff"; 
}

绘制矩形

  1. 矩形是唯一一种可以直接在 2D 上下文中绘制的形状
  2. 与矩形有关的方法包括 fillRect()、strokeRect()和 clearRect()。这三个方法都能接收 4 个参数:矩形的 x 坐标、矩形的 y 坐标、矩形宽度和矩形高度。这些参数的单位都是像素。
  • fillRect()方法在画布上绘制的矩形会填充指定的颜色。填充的颜色通过 fillStyle 属性指定
  • strokeRect()方法在画布上绘制的矩形会使用指定的颜色描边。描边颜色通过 strokeStyle 属性指定
  • clearRect()方法用于清除画布上的矩形区域,用处在于把绘制上下文中的某一矩形区域变透明,例如可以实现把某个形状切掉一块

绘制路径

  1. 要绘制路径,首先必须调用 beginPath()方法,表示要开始绘制新路径。然后,再通过调用下列方法来实际地绘制路径。
  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)为圆心绘制一条弧线,弧线半径为 radius,起始和结束角度(用弧度表示)分别为 startAngle 和endAngle。最后一个参数表示 startAngle 和 endAngle 是否按逆时针方向计算,值为 false表示按顺时针方向计算。
  • arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并且以给定的半径 radius 穿过(x1,y1)。  bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x,y)为止,并且以(c1x,c1y)和(c2x,c2y)为控制点。
  • lineTo(x, y):从上一点开始绘制一条直线,到(x,y)为止。
  • moveTo(x, y):将绘图游标移动到(x,y),不画线。
  • quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)作为控制点。
  • rect(x, y, width, height):从点(x,y)开始绘制一个矩形,宽度和高度分别由 width 和height 指定。这个方法绘制的是矩形路径,而不是 strokeRect()和 fillRect()所绘制的独立的形状。
  1. 创建完路径后,如果想绘制一条连接到路径起点的线条,可以调用closePath();
  2. 如果路径已经完成,你想用 fillStyle 填充它,可以调用 fill()方法。
  3. 可以调用 stroke()方法对路径描边,描边使用的是 strokeStyle
  4. 调用 clip(),这个方法可以在路径上创建一个剪切区域
// 一个不带数字的简易时钟
//html代码
A drawing of something.

//js代码
var drawing = document.getElementById("drawing"); 
//确定浏览器支持元素
if (drawing.getContext){ 
 var context = drawing.getContext("2d"); 
 //开始路径
 context.beginPath(); 
 //绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false); 
//绘制内圆
context.moveTo(194, 100); 
context.arc(100, 100, 94, 0, 2 * Math.PI, false); 
//绘制分针
context.moveTo(100, 100); 
context.lineTo(100, 15); 
//绘制时针
context.moveTo(100, 100); 
context.lineTo(35, 100); 
 //描边路径
 context.stroke(); 
}
  1. isPointInPath()的方法。这个方法接收 x 和 y 坐标作为参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上

绘制文本

  1. 绘制文本主要有两个方法:fillText()和 strokeText()。这两个方法都可以接收 4 个参数:要绘制的文本字符串、x 坐标、y 坐标和可选的最大像素宽度。而且,这两个方法都以下列 3 个属性为基础。
  • font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如"10px Arial"。
  • textAlign:表示文本对齐方式。可能的值有"start"、“end”、“left”、“right"和"center”。建议使用"start"和"end",不要使用"left"和"right",因为前两者的意思更稳妥,能同时适合从左到右和从右到左显示(阅读)的语言。
  • textBaseline:表示文本的基线。可能的值有"top"、“hanging”、“middle”、“alphabetic”、“ideographic"和"bottom”。
  1. fillText()方法使用fillStyle 属性绘制文本,而 strokeText()方法使用 strokeStyle 属性为文本描边
context.font = "bold 14px Arial"; 
context.textAlign = "center"; 
context.textBaseline = "middle"; 
context.fillText("12", 100, 20);
  1. 确定文本大小的方法 measureText()。这个方法接收一个参数,即要绘制的文本;返回一个 TextMetrics对象。返回的对象目前只有一个 width 属性

变换

  1. 可以通过如下方法来修改变换矩阵
  • rotate(angle):围绕原点旋转图像 angle 弧度。
  • scale(scaleX, scaleY):缩放图像,在 x 方向乘以 scaleX,在 y 方向乘以 scaleY。scaleX和 scaleY 的默认值都是 1.0。
  • translate(x, y):将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点。
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方式是乘以如下矩阵。
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用 transform()。
  1. 如果将来还要返回某组属性与变换的组合,可以调用 save()方法。调用这个方法后,当时的所有设置都会进入一个栈结构,得以妥善保管。然后可以对上下文进行其他修改。等想要回到之前保存的设置时,可以调用 restore()方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。连续调用 save()可以把更多设置保存到栈结构中,之后再连续调用 restore()则可一级一级返回。

绘制图像

  1. drawImage()方法把一幅图像绘制到画布上,可以使用三种不同的参数组合
  • 传入一个 HTML 元素,以及绘制该图像的起点的 x 和 y 坐标
var image = document.images[0]; 
context.drawImage(image, 10, 10);
  • 在上一种方式的基础上,改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和目标高度
//绘制出来的图像大小会变成 20×30 像素
context.drawImage(image, 50, 10, 20, 30);
  • 把图像中的某个区域绘制到上下文中,drawImage()方法的这种调用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度

阴影

  1. 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。这些属性都可以通过 context 对象来修改
  • shadowColor:用 CSS 颜色格式表示的阴影颜色,默认为黑色。
  • shadowOffsetX:形状或路径 x 轴方向的阴影偏移量,默认为 0。
  • shadowOffsetY:形状或路径 y 轴方向的阴影偏移量,默认为 0。
  • shadowBlur:模糊的像素数,默认 0,即不模糊。

渐变

  1. 要创建一个新的线性渐变,可以调用 createLinearGradient()方法。这个方法接收 4 个参数:起点的 x 坐标、起点的 y 坐标、终点的 x 坐标、终点的 y 坐标。调用这个方法后,它就会创建一个指定大小的渐变,并返回CanvasGradient 对象的实例
  2. 创建了渐变对象后,下一步就是使用 addColorStop()方法来指定色标。这个方法接收两个参数:色标位置和 CSS 颜色值。色标位置是一个 0(开始的颜色)到 1(结束的颜色)之间的数字
//与fillStyle 或 strokeStyle配合使用
var gradient = context.createLinearGradient(30, 30, 70, 70); 
gradient.addColorStop(0, "white"); 
gradient.addColorStop(1, "black");
//绘制渐变矩形
context.fillStyle = gradient; 
context.fillRect(30, 30, 50, 50);
  1. 要创建径向渐变(或放射渐变),可以使用 createRadialGradient()方法。这个方法接收 6 个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的原心(x 和 y)及半径,后三个参数指定的是终点圆的原心(x 和 y)及半径

模式

  1. 模式其实就是重复的图像,可以用来填充或描边图形。要创建一个新模式,可以调用createPattern()方法并传入两个参数:一个 HTML 元素和一个表示如何重复图像的字符串。其中,第二个参数的值包括"repeat"、“repeat-x”、“repeat-y"和"no-repeat”。

使用图像数据

  1. 通过 getImageData()取得原始图像数据。这个方法接收4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度,返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性:width、height 和data。其中 data 属性是一个数组,保存着图像中每一个像素的数据

合成

两个会应用到 2D 上下文中所有绘制操作的属性

  1. globalAlpha 是一个介于 0 和 1 之间的值(包括 0 和 1),用于指定所有绘制的透明度。默认值为 0
  2. globalCompositionOperation 表示后绘制的图形怎样与先绘制的图形结合。这个属性的值是字符串[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AHBOwo5K-1569921382455)(JavaScript高级程序设计_files/3.jpg)]

WebGL,暂时略过

类型化数组

WebGL上下文

支持

HTML5脚本编程

跨文档消息传递

  1. 跨文档消息传送(cross-document messaging)简称为 XDM,指的是在来自不同域的页面间传递消息
  2. XDM 的核心是 postMessage()方法,接收两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方
//注意:所有支持 XDM 的浏览器也支持 iframe 的 contentWindow 属性
var iframeWindow = document.getElementById("myframe").contentWindow; 
iframeWindow.postMessage("A secret", "http://www.wrox.com");
  1. 接收到 XDM 消息时,会触发 window 对象的 message 事件(异步,接受信息会有延迟),触发 message事件后,传递给 onmessage 处理程序的事件对象包含以下三方面的重要信息
  • data:作为 postMessage()第一个参数传入的字符串数据。
  • origin:发送消息的文档所在的域,例如"http://www.wrox.com"。
  • source:发送消息的文档的 window 对象的代理。这个代理对象主要用于在发送上一条消息的窗口中调用 postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是window。不能通过这个代理对象访问 window 对象的其他任何信息

原生拖放,按住鼠标不放就可以拖动它

拖放事件

  1. 拖动某元素时,将依次触发下列事件
  • dragstart ,按下鼠标键并开始移动鼠标时
  • drag ,在元素被拖动期间会持续触发该事件
  • dragend,拖动停止时
  1. 当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:
  • dragenter ,只要有元素被拖动到放置目标上才回触发
  • dragover ,在被拖动的元素还在放置目标的范围内移动时,就会持续触发该事件
  • dragleave 或 drop,元素被拖出了放置目标

自定义放置目标

有些元素默认是不允许放置的,可以把任何元素变成有效的放置目标,方法是重写 dragenter 和 dragover 事件的默认行为

dataTransfer对象

  1. dataTransfer 对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据,它是事件对象的属性,所以只能在拖放事件的事件处理程序中访问 dataTransfer 对象
  2. dataTransfer 对象有两个主要方法:getData()和 setData()

dropEffect与effectAllowed

  1. 通过 dropEffect 属性可以知道被拖动的元素能够执行哪种放置行为
  • “none”:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。
  • “move”:应该把拖动的元素移动到放置目标。
  • “copy”:应该把拖动的元素复制到放置目标。
  • “link”:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有 URL)。
  1. dropEffect 属性只有搭配 effectAllowed 属性才有用。effectAllowed 属性表示允许拖动元素的哪种 dropEffect,effectAllowed 属性可能的值如下
  • “uninitialized”:没有给被拖动的元素设置任何放置行为。
  • “none”:被拖动的元素不能有任何行为。
  • “copy”:只允许值为"copy"的 dropEffect。
  • “link”:只允许值为"link"的 dropEffect。
  • “move”:只允许值为"move"的 dropEffect。
  • “copyLink”:允许值为"copy"和"link"的 dropEffect。
  • “copyMove”:允许值为"copy"和"move"的 dropEffect。
  • “linkMove”:允许值为"link"和"move"的 dropEffect。
  • “all”:允许任意 dropEffect。

可拖动

  1. draggable 属性,表示元素是否可以拖动,图像和链接的 draggable 属性自动被设置成了 true,而其他元素这个属性的默认值都是 false,要改变可以设置

其他成员

媒体元素,和。

属性

  1. 和共有属性:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRluMNtW-1569921382457)(JavaScript高级程序设计_files/4.jpg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mthnKwcC-1569921382459)(JavaScript高级程序设计_files/5.jpg)]

事件

媒体元素相关的事件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5wv1Wxv-1569921382460)(JavaScript高级程序设计_files/8.jpg)]

自定义媒体播放器

  1. 使用和元素的 play()和 pause()方法,可以手工控制媒体文件的播放。组合使
    用属性、事件和这两个方法,很容易创建一个自定义的媒体播放器

检测编解码器的支持情况

  1. canPlayType()方法,该方法接收一种格式/编解码器字符串,返回"probably"、“maybe"或”"( 空字符串)

Audio类型

历史状态管理

错误处理和调试

浏览器报错

IE

火狐

Safari

Opera

Chrome

错误处理

try-catch语句,跟Java一样的

  1. 语法
try{ 
 // 可能会导致错误的代码
} catch(error){ 
 // 在错误发生时怎么处理
}
  1. 运行机制:如果 try 块中的任何代码发生了错误,就会立即退出代码执行过程,然后接着执行 catch 块。此时,catch 块会接收到一个包含错误信息的对象,该对象有一个保存着错误消息的 message 属性
  2. finally 子句,一经使用,其代码无论如何都会执行
  3. 注意:只要代码中包含finally 子句,那么无论try 还是catch 语句块中的return 语句都将被忽略
  4. 错误类型
  • Error ,基类
  • EvalError ,使用 eval()函数而发生异常时被抛出
  • RangeError ,数值超出相应范围时触发
  • ReferenceError ,找不到对象的情况发生,一般是访问不存在的变量
  • SyntaxError ,语法错误
  • TypeError ,类型不符,在变量中保存着意外的类型时,或者在访问不存在的方法时
  • URIError,使用 encodeURI()或 decodeURI(),而 URI 格式不正确时
  1. 当 try-catch 语句中发生错误时,浏览器会认为错误已经被处理了,因而不会通过浏览器的机制记录或报告错误

抛出错误

  1. throw 操作符,用于随时抛出自定义错误。抛出错误时,必须要给 throw 操作符指定一个值,这个值没有类型要求
  2. 在遇到 throw 操作符时,代码会立即停止执行。仅当有 try-catch 语句捕获到被抛出的值时,代码才会继续执行
  3. 通过原生错误类型,可以自定义错误消息
throw new SyntaxError("I don’t like your syntax.");
  1. 可以通过原型链自定义错误类型
function CustomError(message){ 
 this.name = "CustomError"; 
 this.message = message; 
}
CustomError.prototype = new Error(); 
throw new CustomError("My message");
  1. 抛出错误的时机
function process(values){ 
 if (!(values instanceof Array)){ 
 throw new Error("process(): Argument must be an array."); 
 } 
 values.sort(); 
 for (var i=0, len=values.length; i < len; i++){ 
 if (values[i] > 100){ 
 return values[i]; 
 } 
 } 
 return -1; 
}
  1. 抛出错误与使用try-catch,只应该捕获那些你确切地知道该如何处理的错误。捕获错误的目的在于避免浏览器以默认方式处理它们;而抛出错误的目的在于提供错误发生具体原因的消息

错误(error)事件

任何没有通过 try-catch 处理的错误都会触发 window 对象的 error 事件,在任何 Web 浏览器中,onerror 事件处理程序都不会创建 event 对象,但它可以接收三个参数:错误消息、错误所在的 URL 和行号。多数情况下,只有错误消息有用

处理错误的策略

常见的错误类型

  1. 类型转换错误
  2. 数据类型错误
  3. 通信错误

区分致命错误和非致命错误

  1. 对于非致命错误,可以根据下列一或多个条件来确定:
  • 不影响用户的主要任务;
  • 只影响页面的一部分;
  • 可以恢复;
  • 重复相同操作可以消除错误。
  1. 致命错误:
  • 应用程序根本无法继续运行;
  • 错误明显影响到了用户的主要操作;
  • 会导致其他连带错误

把错误记录到服务器,错误日志

  1. 要建立这样一种 JavaScript 错误记录系统,首先需要在服务器上创建一个页面(或者一个服务器入口点),用于处理错误数据。这个页面的作用无非就是从查询字符串中取得数据,然后再将数据写入错误日志中,这个页面可能使用这样的函数
function logError(sev, msg){ 
 var img = new Image(); 
 img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + 
 encodeURIComponent(msg); 
}
  1. 只要是使用 try-catch 语句,就应该把相应错误记录到日志中
for (var i=0, len=mods.length; i < len; i++){ 
 try { 
 mods[i].init(); 
 } catch (ex){ 
 logError("nonfatal", "Module init failed: " + ex.message); 
 } 
}

调试技术

把消息记录到控制台,console

把消息记录到当前页面,过时啦

抛出错误

  1. 使用throw
function divide(num1, num2){ 
 if (typeof num1 != "number" || typeof num2 != "number"){ 
 throw new Error("divide(): Both arguments must be numbers."); 
 } 
 return num1 / num2; 
}
  1. 对于大型应用程序来说,自定义的错误通常都使用 assert()函数抛出。这个函数接受两个参数,一个是求值结果应该为 true 的条件,另一个是条件为 false 时要抛出的错误
function assert(condition, message){ 
 if (!condition){ 
 throw new Error(message); 
 } 
}
//示例
function divide(num1, num2){ 
 assert(typeof num1 == "number" && typeof num2 == "number", 
 "divide(): Both arguments must be numbers."); 
 return num1 / num2; 
}

常见IE错误

操作终止operation aborted

  1. 在修改尚未加载完成的页面时,就会发生操作终止错误。发生错误时,会出现一个模态对话框,告诉你“操作终止。”单击确定(OK)按钮,则卸载整个页面,继而显示一张空白屏幕

无效字符invalid character

未找到成员Member not found,一般是于垃圾收集例程配合错误所直接导致

未知运行时错误Unknown runtime error,一是把块元素插入到行内元素时,二是访问表格任意部分(、等)的任意属性时

语法错误syntax error

系统无法找到指定资源The system cannot locate the resource specified

JavaScript与XML,跳过

E4X,也是跟XML有关,跳过

JSON,是一种数据格式,不从属于 JavaScript,别的语音也可以用

语法

  1. JSON 的语法可以表示以下三种类型的值
  • 简单值:使用与 JavaScript 相同的语法,可以在 JSON 中表示字符串、数值、布尔值和 null。 但 JSON 不支持 JavaScript 中的特殊值 undefined。 
  • 对象:对象作为一种复杂数据类型,表示的是一组无序的键值对儿。而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值。
  • 数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组。
  1. JSON 不支持变量、函数或对象实例,它就是一种表示结构化数据的格式

简单值

  1. JSON 字符串必须使用双引号

对象

  1. JSON 中的对象要求给属性加引号
{ 
 "name": "Nicholas", 
 "age": 29 
}
  1. 与js的对象字面量的区别
  • 没有声明变量,json中没有变量的概念
  • 没有末尾的分号,因为不是js语句
  1. 属性的值可以是简单值,也可以是复杂类型值包括对象
  2. 同一个对象中绝对不应该出现两个同名属性

数组

  1. JSON 数组采用的就是 JavaScript 中的数组字面量形式
//没有变量和分号
[25, "hi", true]
  1. 对象和数组可以结合使用

解析与序列化

可以把JSON 数据结构解析为有用的 JavaScript 对象,代码精简

json对象

  1. JSON 对象有两个方法:stringify()和 parse()。在最简单的情况下,这两个方法分别用于把JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值
  2. stringify()示例
var book = { 
 title: "Professional JavaScript", 
 authors: [ 
 "Nicholas C. Zakas" 
 ], 
 edition: 3, 
 year: 2011 
 }; 
var jsonText = JSON.stringify(book);
  • 默认情况下,JSON.stringify()输出的 JSON 字符串不包含任何空格字符或缩进,因此保存在 jsonText 中的字符串如下所示:
{"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3, 
"year":2011}
  • 在序列化 JavaScript 对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined 的任何属性也都会被跳过。结果中最终都是值为有效 JSON 数据类型的实例属性
  1. parse()示例
//创建与 book 类似的对象
var bookCopy = JSON.parse(jsonText);
  • book 与 bookCopy 具有相同的属性,但它们是两个独立的、没有任何关系的对象

序列化选项

  1. JSON.stringify()除了要序列化的 JavaScript 对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化 JavaScript 对象,第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进
  2. 过滤结果
  • 如果过滤器参数是数组,那么 JSON.stringify()的结果中将只包含数组中列出的属性
var book = { 
 "title": "Professional JavaScript", 
 "authors": [ 
 "Nicholas C. Zakas" 
 ], 
 edition: 3, 
 year: 2011 
 }; 
var jsonText = JSON.stringify(book, ["title", "edition"]);

//json结果
{"title":"Professional JavaScript","edition":3}
  • 第二个参数是函数,传入的函数接收两个参数,属性(键)名和属性值,函数返回的值就是相应键的值,如果函数返回了undefined,那么相应的属性会被忽略
  1. 字符串缩进,JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。如果这个参数是一个数值,那它表示的是每个级别缩进的空格数
  2. toJSON()方法,在stringify()不能满足序列化需求时,可以给对象定义toJSON()方法,返回其自身的 JSON 数据格式,可以为任何对象添加 toJSON()方法
var book = { 
 "title": "Professional JavaScript", 
 "authors": [ 
 "Nicholas C. Zakas" 
 ], 
 edition: 3, 
 year: 2011, 
 toJSON: function(){
 return this.title; 
  } 
  }; 
 var jsonText = JSON.stringify(book);
  1. 把一个对象传入 JSON.stringify(),序列化该对象的顺序如下
  • 如果存在 toJSON()方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。
  • 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。
  • 对第(2)步返回的每个值进行相应的序列化。
  • 如果提供了第三个参数,执行相应的格式化。

解析选项

  1. JSON.parse()方法也可以接收另一个参数,该参数是一个函数(还原函数),将在每个键值对儿上调用
  2. 如果还原函数返回 undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中,在将日期字符串转换为 Date 对象时,经常要用到还原函数
var book = { 
 "title": "Professional JavaScript", 
 "authors": [ 
 "Nicholas C. Zakas" 
 ], 
 edition: 3, 
 year: 2011, 
 releaseDate: new Date(2011, 11, 1) 
 }; 
var jsonText = JSON.stringify(book); 
var bookCopy = JSON.parse(jsonText, function(key, value){ 
 if (key == "releaseDate"){ 
 return new Date(value); 
 } else { 
 return value; 
 }
 });

Ajax与Comet

Ajax能够向服务器请求额外的数据而无须卸载页面, 技术的核心是 XMLHttpRequest 对象(简称 XHR)

XMLHttpRequest 对象

  1. IE7以前使用 MSXML 库中的 XHR 对象
//适用于 IE7 之前的版本
function createXHR(){ 
 if (typeof arguments.callee.activeXString != "string"){ 
 var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", 
 "MSXML2.XMLHttp"], 
 i, len; 
 for (i=0,len=versions.length; i < len; i++){ 
 try { 
 new ActiveXObject(versions[i]); 
 arguments.callee.activeXString = versions[i]; 
 break; 
 } catch (ex){ 
 //跳过
 } 
 } 
 } 
 return new ActiveXObject(arguments.callee.activeXString); 
}
  1. IE7之后用XMLHttpRequest 构造函数。
var xhr = new XMLHttpRequest();
  1. 兼容IE7与新的
function createXHR(){ 
 if (typeof XMLHttpRequest != "undefined"){ 
 return new XMLHttpRequest(); 
 } else if (typeof ActiveXObject != "undefined"){ 
 if (typeof arguments.callee.activeXString != "string"){ 
 var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", 
 "MSXML2.XMLHttp"], 
 i, len; 
 for (i=0,len=versions.length; i < len; i++){ 
 try { 
 new ActiveXObject(versions[i]); 
 arguments.callee.activeXString = versions[i]; 
 break; 
 } catch (ex){ 
 //跳过
 } 
 } 
 } 
 return new ActiveXObject(arguments.callee.activeXString); 
 } else { 
 throw new Error("No XHR object available."); 
 } 
}

XHR的用法

  1. 使用 XHR 对象时,要调用的第一个方法是 open(),它接受 3 个参数:要发送的请求的类型(“get”、"post"等)、请求的 URL 和表示是否异步发送请求的布尔值
//启动一个针对 example.php 的 GET 请求
xhr.open("get", "example.php", false);
  • URL相对于执行代码的当前页面(当然也可以使用绝对路径)
  • 调用 open()方法并不会真正发送请求,而只是启动一个请求以备发送
  • 只能向同一个域中使用相同端口和协议的 URL 发送请求
  1. 要发送特定的请求,必须像下面这样调用 send()方法将请求发送到服务器:send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入 null.
xhr.open("get", "example.txt", false); 
xhr.send(null);
  • 这次请求是同步的,JavaScript 代码会等到服务器响应之后再继续执行
  • 收到响应后,响应的数据会自动填充 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); 
}
  1. 发送异步请求,此时,可以检测 XHR 对象的 readyState 属性,该属性表示请求/响应过程的当前活动阶段,这个属性的取值有
  • 0:未初始化。尚未调用 open()方法。
  • 1:启动,服务器连接已经建立。已经调用 open()方法,但尚未调用 send()方法。
  • 2:发送。已经调用 send()方法,但尚未接收到响应。
  • 3:接收。已经接收到部分响应数据。
  • 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了
  1. 只要 readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件,通常,我们只对 readyState 值为 4 的阶段感兴趣,因为这时所有数据都已经就绪,注意必须在调用 open()之前指定 onreadystatechange事件处理程序才能确保跨浏览器兼容性
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);
  1. 在接收到响应之前还可以调用 abort()方法来取消异步请求
//XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性
xhr.abort();

HTTP头部信息

  1. 默认情况下,在发送 XHR 请求的同时,还会发送下列头部信息。
  • Accept:浏览器能够处理的内容类型。
  • Accept-Charset:浏览器能够显示的字符集。
  • Accept-Encoding:浏览器能够处理的压缩编码。
  • Accept-Language:浏览器当前设置的语言。
  • Connection:浏览器与服务器之间连接的类型。
  • Cookie:当前页面设置的任何 Cookie。
  • Host:发出请求的页面所在的域 。
  • Referer:发出请求的页面的 URI。注意,HTTP 规范将这个头部字段拼写错了,而为保证与规范一致,也只能将错就错了。(这个英文单词的正确拼法应该是 referrer。)
  • User-Agent:浏览器的用户代理字符串。
  1. 使用 setRequestHeader()方法可以设置自定义的请求头部信息。这个方法接受两个参数:头部字段的名称和头部字段的值,要成功发送请求头部信息,必须在调用 open()方法之后且调用 send()方法之前调用 setRequestHeader()
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.php", true); 
 xhr.setRequestHeader("MyHeader", "MyValue"); 
 xhr.send(null);
  1. 调用 XHR 对象的 getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用 getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。
var myHeader = xhr.getResponseHeader("MyHeader"); 
var allHeaders = xhr.getAllResponseHeaders();

GET请求

  1. 使用 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请求

  1. 在 open()方法第一个参数的位置传入"post",就可以初始化一个 POST 请求
xhr.open("post", "example.php", true);
  1. 发送 POST 请求的第二步就是向 send()方法中传入某些数据

XMLHttpRequest 2 级

FormData

  1. FormData 为序列化表单以及创建与表单格式相同的数据(用于通过 XHR 传输)提供了便利。
var data = new FormData(); 
//append()方法接收两个参数:键和值,分别对应表单字段的名字和字段中包含的值
data.append("name", "Nicholas");
//用表单元素的数据预先向其中填入键值对儿
var data = new FormData(document.forms[0]);
  1. 创建了 FormData 的实例后,可以将它直接传给 XHR 的 send()方法
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); 
 var form = document.getElementById("user-info");
 xhr.send(new FormData(form));

超时设定,兼容性差

  1. timeout 属性,表示请求在等待响应多少毫秒之后就终止,在给timeout 设置一个数值后,如果在规定的时间内浏览器还没有接收到响应,那么就会触发 timeout 事件,进而会调用 ontimeout 事件处理程序

overrideMimeType()方法

  1. overrideMimeType()方法,用于重写 XHR 响应的 MIME 类型

进度事件,了解就好

  1. 有6个进度事件
  • loadstart:在接收到响应数据的第一个字节时触发。
  • progress:在接收响应期间持续不断地触发。
  • error:在请求发生错误时触发。
  • abort:在因为调用 abort()方法而终止连接时触发。
  • load:在接收到完整的响应数据时触发。
  • loadend:在通信完成或者触发 error、abort 或 load 事件后触发。
  1. 每个请求都从触发 loadstart 事件开始,接下来是一或多个 progress 事件,然后触发 error、abort 或 load 事件中的一个,最后以触发 loadend 事件结束。

load事件

  1. load 事件,用以替代 readystatechange 事件。响应接收完毕后将触发 load 事件,因此也就没有必要去检查 readyState 属性
  2. onload 事件处理程序会接收到一个 event 对象,其 target 属性就指向 XHR 对象实例,因而可以访问到 XHR 对象的所有方法和属性
  3. 为保证兼容性,还是要检查status
var xhr = createXHR(); 
xhr.onload = function(){ 
 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ 
 alert(xhr.responseText); 
 } else { 
 alert("Request was unsuccessful: " + xhr.status); 
 } 
}; 
xhr.open("get", "altevents.php", true); 
xhr.send(null);

progress事件

  1. progress 事件,这个事件会在浏览器接收新数据期间周期性地触发,onprogress 事件处理程序会接收到一个 event 对象,其 target 属性是 XHR 对象,但包含着三个额外的属性:lengthComputable、position 和 totalSize
  • lengthComputable是一个表示进度信息是否可用的布尔值
  • position 表示已经接收的字节数
  • totalSize 表示根据Content-Length 响应头部确定的预期字节数
//运用示例
var xhr = createXHR(); 
xhr.onload = function(event){ 
 if ((xhr.status >= 200 && xhr.status < 300) || 
 xhr.status == 304){ 
 alert(xhr.responseText); 
 } else { 
 alert("Request was unsuccessful: " + xhr.status); 
 } 
}; 
xhr.onprogress = function(event){ 
 var divStatus = document.getElementById("status"); 
 if (event.lengthComputable){ 
 divStatus.innerHTML = "Received " + event.position + " of " + 
 event.totalSize +" bytes"; 
 } 
}; 
xhr.open("get", "altevents.php", true); 
xhr.send(null);

跨资源共享CORS(Cross-Origin Resource Sharing

  1. 默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源,CORS的出现是为了实现合理的跨域请求
  2. CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败

你可能感兴趣的:(读书笔记)