JavaScript高级程序设计 第4版(中文高清)扫描版

JavaScript高级程序设计 第4版(中文高清)扫描版核心ECMAScript文档对象模型DOM浏览器对象模型BOMECMAScript定义语言的基础规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1. JavaScript组成

  1. 核心ECMAScript
  2. 文档对象模型DOM
  3. 浏览器对象模型BOM

1.2.1 ECMAScript

定义语言的基础
规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象
js nodejs 都实现了ECMAScript

1.2.2 DOM

文档对象模型 Document Object Model

针对XML但经扩展用于HTML的应用程序编程接口(API)
把整个页面映射为多层节点结构,每个节点包含不同类型的数据。
借助DOM API,可删除,添加,替换,修改任何节点

1.2.2.2 DOM级别

DOM1:

  1. DOM核心:如何映射文档结构,简化对文档任意部分的访问操作
  2. DOM HTML

DOM2:

  1. 鼠标和用户界面事件,范围,便利(迭代DOM文档的方法)
  2. 对css的支持

DOM3:

  1. 引入统一方式加载和保存文档
  2. DOM验证

1.2.3 BOM

访问和操作浏览器窗口和子窗口frame,通常把任何特定于浏览器的扩展都归于BOM范畴。

  • 弹出浏览器窗口的能力
    移动,缩放,关闭浏览器的能力
    navigator:提供浏览器的详尽信息
    location:提供浏览器加载页面的详尽信息
    screen:提供关于用户屏幕分辨率的详尽信息
    performance:提供浏览器内存占用,导航行为,时间统计的详尽信息
    cookies:
    XHLHttpRepuest ActiveXObject

2. HTML中的JavaScript

2.1 <script>元素

  1. async 异步脚本 脚本不需等待其他脚本,不阻碍文档渲染,异步加载 立即下载脚本,但不妨碍页面其他操作 一定在load事件前执行
  2. charset 代码字符集,浏览器不在乎它的值
  3. crossorigin 配置相关请求的CORS设置。默认不适用CORS设置。corossorigin=”anonymous”配置文件请求不必设置凭据标志。corossorigin=”use-crednetials”设置凭据标志
  4. defer 延迟脚本 脚本可延迟到文档完全解析和显示后执行。立即下载,延迟执行
  5. integrity 允许对接收到的资源的签名与指定的加密签名验证资源完整性
  6. src 文件路径url
  7. type 语言内容类型MIME类型。这个值始终是“text/javascript”

不存在defer,saync属性,浏览器会按script在页面中的先后顺序依次解析,第一个解析完后,第二个才会被解析。

对不推迟执行的脚本,必须解释完位于js标签内的的全部代码,才能继续渲染页面

在解释外部js文件时,页面会被阻塞(阻塞时间包含文件下载时间)

可跨域取得相应资源,不受同源策略限制。

放在head中,必须等JavaScript都被下载,解析,执行完后才呈现页面

把脚本放在页面底部

2.1.4 动态加载脚本

let script =document.createElemnet('script')
script.src='aa.js'
document.head.apendChild(script)

会严重影响性能

在XHTML中的用法

XHTML模式会在页面的MIME类型被指定为application/xhtml+xml时触发。

a < b中的 < 在XHTML中被当作新标签解析。但作为标签,< 后不能跟空格,
解决:

  1. &lt; 替换 <
  2. 用CData片段包含JavaScript,包含不需要解析的任意个数的文本内容
<script> //hack,平稳退化 //<![ CADATA[ function compare(){ 
     } //]]> </script>

2.3 文档模式

通过文档类型 doctype切换实现

主要体现在css渲染方面,但对js也会有一些副作用。

  • 混杂模式 :省略doctype声明 未发现文档类型声明,默认开启混杂模式,
  • 标准模式
    开启标准模式:
<!--HTML5-->
<!DOCTYPE html>

  • 标准准模式(处理图片间隙,表格中使用)

2.4 <noscript>元素

js被禁用时出现

3. 语言基础

3.1 语法

区分大小写

标识符:

  • 第一个字符必须是字母,下划线(_),美元符号($)
  • 剩余字符可以说字母,下划线,美元符,数字
  • 按惯例使用驼峰式命名

注释

C语言风格

严格模式 strict mode

js不同解析和执行模式,ECMAScript3中的不确定行为得到处理,不安全的操作会抛出错误
整个脚本启用,顶部添加
“use strict”;
指定函数在严格模式下执行

语句

末尾;
语句块{}

关键字

break do instanceof typeof case else new var catch finally return void continue for switch while debugger* function this with default if throw
delete in try

保留字

abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native

3.3 变量

var

不初始化时,变量保存undefined
函数作用域,在函数退出时被销毁
函数内定义时省略var,可创建一个全局变量(不推荐,全局变量很难维护)
严格模式下不能定义eval,arguments的变量

声明提升,自动提升到函数作用域的顶部

let

块作用域
不允许出现冗余声明
不会在作用域中被提升
在全局作用域中生命的变量不会成为window对象的属性

  • 条件声明:不确定前面是否声明过同名变量,可假定它还没声明。

不可能检查前面受否已经使用let声明过同名变量,不可能在没有声明的情况下声明它
不能使用let进行条件声明

<script>
var name="cjr"
let age=23
<script>
<script>
//不需要检测前面是否声明过同名变量
var name="sxl"
//
let age=20
  1. for循环中的let

let之前for循环中的变量会渗透到for循环外部

for(var i=0;i<=5;i++){ 
   
}
//
console.log(i)	//6

for(let i=0;i<=5;i++){ 
   
}
//
console.log(i)	//报错

var 对迭代变量的奇特声明和修改

for(var i=0;i<5;i++){ 
   
setTimeout(()=>{ 
   console.log(i),0}	//5,5,5,5,5,5
}

是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时
逻辑时,所有的i 都是同一个变量,因而输出的都是同一个最终值。
而在使用let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。
每个setTimeout 引用的都是不同的变量实例,所以console.log 输出的是我们期望的值,也就是循
环执行过程中每个迭代变量的值。

const

const声明变量时必须初始化,尝试修改const声明的变量会报错

声明风格最佳实践

不使用var
优先使用const,

3.4 数据类型

typeof操作符

是一个操作符,不是函数,不需要参数(也可以使用参数)

let aa="cjd"
typeof aa	//string
typeof(aa)	//string
typeof 11	//number

undefined类型

只有一个值,undefined

声明但为初始化
给定变量为声明 调用typeof 也返回undefined

undefined是一个假值,检测时需注意自己检测的是undefined,而不仅仅是一个假值

null类型

只有一个值 null

表示一个空对象的指针

定义的对象 用来保存对象,初始化为null

Boolean类型

true false
true不等于1
Boolean() //将其他类型的值转换为布尔值

let message="hello"
let messageAsBoolean=Boolean(message)
数据类型 转换为true的值 转换为false的值
Boolean true false
String 非空字符串 “”
Number 非零数值 0,NaN
Object 任意对象 null
Undefined N/A(不存在) undefined

if等流程语句会自动执行其他类型到布尔值的转换

Number

  • 八进制

第一位必须为0,跟0-7

070 > 56;

严格模式下无效

  • 十六进制

数值前缀为0x(区分大小写),数字不区分大小写
0x 跟0-9 A-F(也可小写)

在算术计算时,始终被转成十进制

  • 浮点数

保存浮点数的内存空间为整数的两倍,1. 10.0将被转换为整数
对于极大极小的数,用e/E(科学计数法)表示。

3.12e7 31200000 3.12乘10 7
浮点数的最高精度17位小数

范围
Infinity

NaN
isNaN() 任何不能被转换为数值的值使函数返回true
数值转换
Number() 转string时必须全部为数字才能转为有效数字

转型函数,可用于任何数据类型
转换规则:
 布尔值,true 转换为1,false 转换为0。
 数值,直接返回。
 null,返回0。
 undefined,返回NaN。
 字符串,应用以下规则。
 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。
因此,Number(“1”)返回1,Number(“123”)返回123,Number(“011”)返回11(忽略前面
的零)。
 如果字符串包含有效的浮点值格式如”1.1″,则会转换为相应的浮点值(同样,忽略前面的零)。
 如果字符串包含有效的十六进制格式如”0xf”,则会转换为与该十六进制值对应的十进制整
数值。
 如果是空字符串(不包含字符),则返回0。
 如果字符串包含除上述情况之外的其他字符,则返回NaN。
 对象,调用valueOf()方法,并按照上述规则转换返回的值。如果转换结果是NaN,则调用
toString()方法,再按照转换字符串的规则转换。

parseInt() 必须以数字开头

从第一个非空字符开始转换,如第一个字符不是数值,+,-,立即返回NaN。碰到字符串尾,非数值字符结束。
es5不具备解析八进制的功能
第二个参数:基数 ,多少进制

paeseFloat()

只解析十进制

string

1. 字符字面量

转义序列

字面量 含义
\n 换行

将一个值转换为字符串

toString()

null undefined没有
参数:基数

String()

能将任意类型的值转换为字符串

模板字符串

5. 插值

${}

7.原始字符串

String.raw`\u00A9`

Symbol类型

符号类型
确保对象属性使用唯一标识

  1. 基本用用法
let sym=Symbol()
let otherSym=Symbol()
smy == otherSmy	//false

let fooSmybol=Symbol('foo')
  1. 使用全局符号注册表
let sym=Symbol.for('foo')
let otherSym=Symbol.for('foo')
smy === otherSmy	//true

Symbol.keyFor('sym')
  1. 符号作为属性

Object类型

new Object()
Object类型是他实例的基础。Object类型所具有的任何属性,方法同样存在具体的对象中。
object实例的属性方法:

  • Constructor 构造函数,创建当前对象的函数
  • hasOwnProperty(propertyName) 判断当前实例对象(不是原型)上是否存在给定的属性
  • isProtyotypeOf(object) 判断当前对象是否为另一个对象的原型
  • propertyIsEnumerable(propertyName) 判断给定的属性是否柯贝for-in语句枚举
  • toLocalString()
  • toString() 返回对象的字符串表示
  • valueOf()

3.5 操作符

3.5.1 一元操作符

  1. ++ / –

前缀版:
变量的值会在语句被求值前改变
后缀版:
递增递减在语句被求值后才改变

规则:
不限于整数
 对于字符串,如果是有效的数值形式,则转换为数值再应用改变。变量类型从字符串变成数值。
 对于字符串,如果不是有效的数值形式,则将变量的值设置为NaN 。变量类型从字符串变成
数值。
 对于布尔值,如果是false,则转换为0 再应用改变。变量类型从布尔值变成数值。
 对于布尔值,如果是true,则转换为1 再应用改变。变量类型从布尔值变成数值。
 对于浮点值,加1 或减1。
 如果是对象,则调用其(第5 章会详细介绍的)valueOf()方法取得可以操作的值。对得到的
值应用上述规则。如果是NaN,则调用toString()并再次应用其他规则。变量类型从对象变成
数值。


  1. + / –

3.5.2 位操作符

  1. 有符号整数
    32位表示数值的符号
    负数:二进制补码
    • 绝对值的二进制码
    • 反码:
    • 反码加1
  2. 按位非NOT
    波浪线 ~
    返回数值的反码:操作数的负值减1
    num
    – num-1
  3. 按位与AND
    &
    都是1时才返回1
  4. 按位或 OR
    有一个1就返回1
  5. 按位异或XOR
    只有一个1才返回1
  6. 左移
    <<
  7. 有符号右移

3.5.3布尔操作符

  1. 非 !
     如果操作数是对象,则返回false。
     如果操作数是空字符串,则返回true。
     如果操作数是非空字符串,则返回false。
     如果操作数是数值0,则返回true。
     如果操作数是非0 数值(包括Infinity),则返回false。
     如果操作数是null,则返回true。
     如果操作数是NaN,则返回true。
     如果操作数是undefined,则返回true。
  2. 与 &&
     如果第一个操作数是对象,则返回第二个操作数。
     如果第二个操作数是对象,则只有第一个操作数求值为true 才会返回该对象。
     如果两个操作数都是对象,则返回第二个操作数。
     如果有一个操作数是null,则返回null。
     如果有一个操作数是NaN,则返回NaN。
     如果有一个操作数是undefined,则返回undefined。
    逻辑与操作符是一种短路操作符,意思就是如果第一个操作数决定了结果,那么永远不会对第二个
    操作数求值。对逻辑与操作符来说,如果第一个操作数是false,那么无论第二个操作数是什么值,结
    果也不可能等于true。
  3. 或 ||
     如果第一个操作数是对象,则返回第一个操作数。
     如果第一个操作数求值为false,则返回第二个操作数。
     如果两个操作数都是对象,则返回第一个操作数。
     如果两个操作数都是null,则返回null。
     如果两个操作数都是NaN,则返回NaN。
     如果两个操作数都是undefined,则返回undefined。
    同样与逻辑与类似,逻辑或操作符也具有短路的特性。只不过对逻辑或而言,第一个操作数求值为
    true,第二个操作数就不会再被求值了。

3.5.4 乘性操作符

  1. *
     如果操作数都是数值,则执行常规的乘法运算,即两个正值相乘是正值,两个负值相乘也是正
    值,正负符号不同的值相乘得到负值。如果ECMAScript 不能表示乘积,则返回Infinity 或
    -Infinity。
     如果有任一操作数是NaN,则返回NaN。
     如果是Infinity 乘以0,则返回NaN。
     如果是Infinity 乘以非0 的有限数值,则根据第二个操作数的符号返回Infinity 或-Infinity。
     如果是Infinity 乘以Infinity,则返回Infinity。
     如果有不是数值的操作数,则先在后台用Number()将其转换为数值,然后再应用上述规则。
  2. 除 /
     如果操作数都是数值,则执行常规的除法运算,即两个正值相除是正值,两个负值相除也是正
    值,符号不同的值相除得到负值。如果ECMAScript不能表示商,则返回Infinity 或-Infinity。
     如果有任一操作数是NaN,则返回NaN。
     如果是Infinity 除以Infinity,则返回NaN。
     如果是0 除以0,则返回NaN。
     如果是非0 的有限值除以0,则根据第一个操作数的符号返回Infinity 或-Infinity。
     如果是Infinity 除以任何数值,则根据第二个操作数的符号返回Infinity 或-Infinity。
     如果有不是数值的操作数,则先在后台用Number()函数将其转换为数值,然后再应用上述规则。
  3. 取模操作符 %
     如果操作数是数值,则执行常规除法运算,返回余数。
     如果被除数是无限值,除数是有限值,则返回NaN。
     如果被除数是有限值,除数是0,则返回NaN。
     如果是Infinity 除以Infinity,则返回NaN。
     如果被除数是有限值,除数是无限值,则返回被除数。
     如果被除数是0,除数不是0,则返回0。
     如果有不是数值的操作数,则先在后台用Number()函数将其转换为数值,然后再应用上述规则。

3.5.5 指数操作符

Math.pow() **

Math.pow(3,2)	//9 不推荐使用
3**2

3.5.6 加性操作符

  1. 加法操作符
    加法操作符(+)用于求两个数的和,比如:
    let result = 1 + 2;
    如果两个操作数都是数值,加法操作符执行加法运算并根据如下规则返回结果:
     如果有任一操作数是NaN,则返回NaN;
     如果是Infinity 加Infinity,则返回Infinity;
     如果是-Infinity 加-Infinity,则返回-Infinity;
     如果是Infinity 加-Infinity,则返回NaN;
     如果是+0 加+0,则返回+0;
     如果是-0 加+0,则返回+0;
     如果是-0 加-0,则返回-0。
    不过,如果有一个操作数是字符串,则要应用如下规则:
    如果两个操作数都是字符串,则将第二个字符串拼接到第一个字符串后面;
     如果只有一个操作数是字符串,则将另一个操作数转换为字符串,再将两个字符串拼接在一起。
    如果有任一操作数是对象、数值或布尔值,则调用它们的toString()方法以获取字符串,然后再
    应用前面的关于字符串的规则。对于undefined 和null,则调用String()函数,分别获取
    “undefined”和”null”。
  2. 减法操作符(-)也是使用很频繁的一种操作符,比如:
    let result = 2 – 1;
    与加法操作符一样,减法操作符也有一组规则用于处理ECMAScript 中不同类型之间的转换。
     如果两个操作数都是数值,则执行数学减法运算并返回结果。
     如果有任一操作数是NaN,则返回NaN。
     如果是Infinity 减Infinity,则返回NaN。
     如果是-Infinity 减-Infinity,则返回NaN。
     如果是Infinity 减-Infinity,则返回Infinity。
     如果是-Infinity 减Infinity,则返回-Infinity。
     如果是+0 减+0,则返回+0。
     如果是+0 减-0,则返回-0。
     如果是-0 减-0,则返回+0。
     如果有任一操作数是字符串、布尔值、null 或undefined,则先在后台使用Number()将其转
    换为数值,然后再根据前面的规则执行数学运算。如果转换结果是NaN,则减法计算的结果是
    NaN。
     如果有任一操作数是对象,则调用其valueOf()方法取得表示它的数值。如果该值是NaN,则
    减法计算的结果是NaN。如果对象没有valueOf()方法,则调用其toString()方法,然后再
    将得到的字符串转换为数值。

3.5.7 关系操作符

小于(<)、大于(>)、小于等于(<=)和大于等于(>=),
用法跟数学课上学的一样。这几个操作符都返回布尔值

 如果操作数都是数值,则执行数值比较。
 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。
 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
 如果有任一操作数是对象,则调用其valueOf()方法,取得结果后再根据前面的规则执行比较。
如果没有valueOf()操作符,则调用toString()方法,取得结果后再根据前面的规则执行比较。
 如果有任一操作数是布尔值,则将其转换为数值再执行比较。
使用关系操作符比较两个字符串时,会发生一个有趣的现象。很多人认为小于意味着“字母顺序靠前”,而大于意味着“字母顺序靠后”,实际上不是这么回事。对字符串而言,关系操作符会比较字符串中对应字符的编码,而这些编码是数值。比较完之后,会返回布尔值。问题的关键在于,大写字母的编码都小于小写字母的编码

3.5.8 相等操作符

1. 相等,不相等	==
先转换再比较
2. 全等,不全等	===
仅比较不转换
  1. 等于和不等于
    ECMAScript 中的等于操作符用两个等于号(==)表示,如果操作数相等,则会返回true。不等于操作符用叹号和等于号(!=)表示,如果两个操作数不相等,则会返回true。这两个操作符都会先进行类型转换(通常称为强制类型转换)再确定操作数是否相等。
    在转换操作数的类型时,相等和不相等操作符遵循如下规则。
     如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false 转换为0,true 转换为1。
     如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。
     如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法取得其原始值,再根据前面的规则进行比较。
    在进行比较时,这两个操作符会遵循如下规则。
     null 和undefined 相等。
     null 和undefined 不能转换为其他类型的值再进行比较。
     如果有任一操作数是NaN,则相等操作符返回false,不相等操作符返回true。记住:即使两
    个操作数都是NaN,相等操作符也返回false,因为按照规则,NaN 不等于NaN。
     如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true。否则,两者不相等。

  2. 全等和不全等
    全等和不全等操作符与相等和不相等操作符类似,只不过它们在比较相等时不转换操作数。全等操作符由3 个等于号(===)表示,只有两个操作数在不转换的前提下相等才返回true

3.5.9 条件操作符 (三目运算符)

? :

3.5.10赋值操作符

简单赋值用等于号(=)表示,将右手边的值赋给左手边的变量,

3.5.11 逗号操作符

,

ES6链判断运算符(?.)和Null判断运算符(??)

语句

详细介绍

if

if(){ 
   
}else{ 
   }

if(){ 
   
}else if(){ 
   
}else{ 
   }

do-while

循环体内的代码至少执行一次

do{ 
   
}while()

while

while(){ 
   
}

for

while无法实现的逻辑,for也无法实现

for(var i=0;i<10;i++){ 
   
}

while循环的简化

for-in

迭代语句,枚举对象的非符号键属性

//与 for 循环一样,这里控制语句中的 const 也不是必需的。但为了确保这个局部变量不被修改,推荐使用 const。
for(const kk in window){ 
   
console.log(kk)
}

ECMAScript 中对象的属性是无序的,因此 for-in 语句不能保证返回对象属性的顺序。
如对象值为null,undefined。for-in抛出错误,或不在执行循环体
如果for-in 循环要迭代的变量是null 或undefined,则不执行循环体。

for-of

迭代语句,用于遍历可迭代对象的元素

for (const el of [2,4,6,8]) { 
   
document.write(el);
}

区别:
for…of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句
for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法:

for-await-of

支持生成期约(promise)的异步可迭代对象

label

label:statement

start:for(var i=0;i<8;i++){ 
   
for(var i=0;i<9;i++){ 
   
if(i==3){ 
   
break start}}
console.log(i)
}

标签将由break,continue语句引用。与循环语句配合使用

break continue

break退出循环执行循环后面的语句
continue退出本次循环,从循环顶部继续执行

var num=0;
outer:
for(var i=0;i<10;i++){ 
   
	for(var j=0;j<10;j++){ 
   
		if(i==5&& j==5){ 
   
			break outer;
		}
		num++;
	}
}

switch

switch ("hello") { 
   
	case "hello":
		alert()
		break;
	case "good":
		break;
	default:
		alert()
}

函数

参数

arguments对象

函数重载

4. 变量,作用域,内存

4.1 基本类型,引用类型

数据类型详细介绍
基本数据类型:Undefined,Null,Boolean,Number,String,Symbol

按值访问,操作的就是储存在变量中的值

引用类型:

复制值时,实际是一个指针,指向存储在堆中的一个对象。两个变量引用同一个对象。

动态属性

储存方式不同

复制

原始值:副本
引用值:

传递参数

都是按值传递

function setName(obj){ 
   
obj.name="nn";
obj=new Object();
obj.name="cc"';
}
var person=new Object()
setName(preson);

对象传递到函数后被复制给obj,函数内部,obj={},即使传入的是一个对象,obj也会按引用来访问。
如是按引用传递,那函数内部重写obj,这个变量引用的是一个局部对象

类型检测

typeof “jj”
[] instanceof Array

作用域链

4.2 执行上下文和作用域

上下文在其全布代码执行完毕后会被销毁。

作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。

内部上下文可通过作用域链访问外部上下文中的一切,但外部上下文无法访问内部的任何东西。

函数参数被认为v是当前上下文中的变量。

作用域增强

try/catch
with

4.3 垃圾回收

标记清除

主流垃圾收集算法
当变量进入上下文,比如在函数
内部声明一个变量时,这个变量会被加上存在于上下文中的标记。而在上下文中的变量,逻辑上讲,永
远不应该释放它们的内存,因为只要上下文中的代码在运行,就有可能用到它们。当变量离开上下文时,
也会被加上离开上下文的标记。

计数引用

但很快就遇到了严重的问题:循环引用

4.3.4 内存管理

  1. 隐藏类和删除操作
  1. 内存泄漏

全局变量
定时器
闭包

  1. 静态分配与对象池

5. 基本引用类型

5.1 Date类型

var now=new Date()
不传参数:当前日期时间
创建特定时间日期对象:传入表示该日期的毫秒数

Date.parse()

参数:表示日期的字符串
返回:相应日期的毫秒数
这个方法的实现因地区而异
美国浏览器支持的格式:

  • “月/日/年”,如”5/23/2019″;
  • “月名 日, 年”,如”May 23, 2019″;
  • “周几 月名 日 年 时:分:秒 时区”,如”Tue May 23 2019 00:00:00 GMT-0700″; 
  • ISO 8601 扩展格式“YYYY-MM-DDTHH:mm:ss.sssZ”,如 2019-05-23T00:00:00(只适用于
    兼容 ES5 的实现)。

如传入的字符串不能表示日期,返回NaN
直接将表示日期的字符串传给Date(),默认调用Date.parse()

Data.UTC()

参数:年,月(0,1),天(1)[,小时(0),分种,秒,毫秒]

方法

toLocalString() 返回与浏览器运行的本地环境一致的日期和时间。
toString() 带时区信息的日期时间

时间日期组件的方法

在这里插入图片描述
在这里插入图片描述

RegExp类型

匹配规则
匹配模式:

  1. g:全局模式,应用于所有字符串
  2. i:不区分大小写模式
  3. m:多行模式

/aa/gi

元字符
( [ { \ ^ $ | ) ] } ? * + .

实例属性

global:是否设置g标志
igonoreCase:
lastIndex:开始搜索下一匹配项的字符位置
multiline:
source:

实例方法

exec()
参数:要应用模式的字符串
返回数组:
index:匹配项在字符串中的位置
input:应用正则匹配的字符串
第一项是与整个模式匹配的字符串,
其他项是与模式中捕获组匹配的字符串

设置了g:每次调用exec()都会在字符串中继续查找新匹配项
不设置:同一字符串多次调用始终返回一个匹配项信息

test()
模式与参数匹配返回true

构造函数的属性

Function类型

函数实际是对象,函数名实际是指向对象的指针,不与某个函数绑定

函数重载

函数声明和函数表达式

解析器会率先执行函数声明,函数表达式必须等到解析器执行到她所在的代码行,才会被真正解释执行

函数的属性和方法

length:函数希望接收的参数个数
prototype:

在特定作用域中调用函数,设置函数体内this的值
严格模式下,this不会转为windows
apply:运行函数的作用域,参数(array,arguments)
call:
bind:

5.3 原始值包装类型

Boolean

new Boolean(false) //true falseObject对象,在布尔表达式中会自动转换为true

永远不要使用 原始布尔值和布尔对象的差别很大

Number

toString()
参数:几进制
返回:相应基数形式的数值字符串

toFixed()
按指定小数位返回数值的字符串表示 ,四舍五入

toExponential()
参数:小数位数
返回以科学计数法表示的数值字符串。

toPrecision()
参数:结果数字中的总位数

let num=10;
num.toString(2);	//1010
num.toFixed(2)		//"10.00"
(10).toString()
num.toExponential(1)	//"1.0e_1"
num.toPrecision(1)	//"1e+1"
num.toPrecision(2)	//"10"

Number.isInteger() //辨别一个数值是否是整数
小数位的0的数是整数

String

详细介绍

字符方法

charAt()

以单字符串的形式返回给定索引位置的字符
参数:基于0的字符位置

"abc".charAt(2)	//c

charCodeAt()

字符编码
返回指定索引位置的码元值

"abc".charCodeAt(2)	//99等于16进制63,c的编码U+0063

fromCharCode()

字符串解码

String.fromCharCode(97,98)	//ab

这个对应关系在扩展到 Unicode 增补字符平面时就不成立了。问题很简单,即 16 位只能唯一表示65 536 个字符。这对于大多数语言字符集是足够了,在 Unicode 中称为基本多语言平面(BMP)。为了表示更多的字符,Unicode 采用了一个策略,即每个字符使用另外 16 位去选择一个增补平面。这种每个字符使用两个 16 位码元的策略称为代理对。

"ab?".length	//4
console.log([..."ab☺de"]); // ["a", "b", "☺", "d", "e"]

codePointAt()

接收 16 位码元的索引并返回该索引位置上的码点(code point)。码点是 Unicode 中一个字符的完整标识。比如,”c”的码点是 0x0063,而”?”的码点是 0x1F60A。码点可能是 16 位,也可能是 32 位,而 codePointAt()方法可以从指定码元位置识别完整的码点。

fromCodePoint()

这个方法接收任意数量的码点,返回对应字符拼接起来的字符串:

字符串操作方法

concat()

将一个或多个字符串拼接起来
不会修改调用它们的字符串

let string1="hello"
let result=string1.concat("word","!")

slice()

根据下标截取字串
返回:调用它们的字符串的一个子字符串
参数:字串开始的位置,[子字符串最后一个字符后面的位置(即该位置之前的字符会被提取出来)]
省略第二个参数都意味着提取到字符串末尾
参数为负数:将负值与字符串的长度相加
不会修改调用它们的字符串,而只会返回提取到的原始新字符串值

substr()

根据长度截取字串
返回:调用它们的字符串的一个子字符串
参数:字串开始的位置,[返回字符个数]
省略第二个参数都意味着提取到字符串末尾
参数为负数:将第一个负值与字符串的长度相加,将第二个负值转换为0
不会修改调用它们的字符串

substring()

  • 根据下标截取字串
  • 返回:调用它们的字符串的一个子字符串
  • 参数:字串开始的位置,[子字符串最后一个字符后面的位置(即该位置之前的字符会被提取出来)]
    省略第二个参数都意味着提取到字符串末尾
    参数为负数:把所有负值转换为0
  • 会将较小的参数作为起点,将较大的参数作为终点。
  • 不改变原始字符串

字符串位置方法

indexOf()
返回位置(如果没找到,则返回-1)

参数:要查找的字符串,[开始搜索的位置]

lastIndexOf()

参数:要查找的字符串,[开始搜索的位置]

字符串包含方法

includes()

  • 整个字符串内查找
    返回一个表示是否包含的布尔值
    可选的第二个参数,表示开始搜索的位置

startsWith()

  • 字符串开头是否是
    可选的第二个参数,表示开始搜索的位置
let mess="foobar"
mess.starrWith("f00")	//true
mess.starrWith("f00",1)	//false

endsWith()

  • 字符串末尾是否是
    收可选的第二个参数,表示应该当作字符串末尾的位置。如果不提供这个参数,
    那么默认就是字符串长度。如果提供这个参数,那么就好像字符串只有那么多字符一样

trim()

删除前置后置空格,返回副本
trimLeft()
trimRight()

repeat()

参数:表示要将字符串复制多少次

padStart() padEnd()

复制字符串,小于指定长度,在相应一边填充,默认空格

参数:长度,[填充字符串]

let str="foo"
str.padStart(4,".")	//"....foo"

迭代与解构

迭代字符串的每个字符

var message="abc"
let stringIterator=message[Symbol.iterator]()
stringIterator.next()
//for循环

解构

var message="abc"
[...message]

大小写转换

转为小写
toLowerCase()
toLocalLowerCase()

转为大写
toUpperCase()
toLocaleUpperCase()

字符串模式匹配方法

match()

本质与exec()相同
参数:正则表达式,RegExp对象
返回数组

let text = "cat, bat, sat, fat";
let pattern = /.at/;
// 等价于pattern.exec(text)
let matches = text.match(pattern);
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0

search()

返回字串中第一个匹配项的索引,没有找到返回-1

let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos); // 1

replace()

参数:第一个参数:RegExp对象或字符串(不会被转换成正则表达式),第二个参数:一个字符串或函数
如果第一个参数是字符串,只会替换第一个子字符串。想要替换所有子字符串,提供一个正则表达式,指定管局g标志。
如第二个参数是字符串,可使用特殊字符序列,将正则表达操作得到的值插入结果字符串

let text = "cat, bat, sat, fat";
let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
console.log(result); // "cond, bond, sond, fond"
字符序列 替换文本
$$ $
$& 匹配整个模式的子字符串。与RegExp.lastMatch的值相同
$’ 匹配子字符串之前的子字符串,与RegExp.leftContext的值相同
$` 匹配子字符串之前的子字符串,与RegExp.rightContext的值相同
$n 匹配第n个捕获组的字符串,n(0~9)。
$nn 匹配第nn个捕获组的子字符串,nn(01~99)。
var text="cat,bat,sat,fat";
result=text.replace(/at/g,"word($$)");

第二个参数可是函数。

  • 在只有一个匹配项的情况下,会向这个函数传递3个参数:与整个模式匹配的字符串,模式的匹配项在字符串中的位置,原始的字符串。
  • 在正则表达式中定义了许多捕获组的情况下,传递给函数的参数依次是:模式的匹配项,第一个捕获组的匹配项,第二个捕获组的匹配项,…,最后两个参数为模式的匹配项在字符串中的位置,原始的字符串。
  • 这个函数应返回一个字符串,表示被替换的匹配项使用函数作为为replace()方法 的 第二个参数可实现更加精细的替换操作。
function htmlEscape(text) { 
   
return text.replace(/[<>"&]/g, function(match, pos, originalText) { 
   
switch(match) { 
   
case "<":
return "&lt;";
case ">":
return "&gt;";
case "&":
return "&amp;";
case "\"":
return "&quot;";
}
});
}

htmlEscape("<p class=\"greeting\">hello<\\/p>")

split()

  • 基于指定分割符多个子字符串,将结果放在数组中。
  • 参数:分隔符:字符串,RegExp对象。 [数组的大小 ]
let colorText = "red,blue,green,yellow"; 
let colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"] 
let colors2 = colorText.split(",", 2); // ["red", "blue"] 
let colors3 = colorText.split(/[^,]+/); // ["", ",", ",", ",", ""]
"red,blue,green".split(/[^\,]+/);	//[^x]不在,x+匹配至少一个

localeCompare()

比较两个字符串,如字符串在字符串参数之前,返回一个负数

‘yello'.localeCompare('zoo')	//-1

formCharCoce()

String构造函数的静态方法
接收一个或多个字符编码,转换为一个字符串。

String.formCharCode(104,101,108);	//"hel"

HTML方法
js动态格式化HTML的需求
anchor(name)
big()
boldd()

5.4 单体内置对象

内置对象:由ES实现提供,不依赖宿主环境,在
不必显示的实例化内置对象,因为他们已经实例化了。Object,Array,String,Global,Math.

Global

这个对象不存在

url编码方法

用于编码统一资源标识符(URI),以便传给浏览器。
有效的 URI 不能包含某些字符,比如空格。使用 URI 编码方法来编码 URI 可以让浏览器能够理解它们,
同时又以特殊的 UTF-8 编码替换掉所有无效字符。

let uri = "http://www.wrox.com/illegal value.js#start"; 
// "http://www.wrox.com/illegal%20value.js#start" 
console.log(encodeURI(uri)); 
// "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start" 
console.log(encodeURIComponent(uri));

encodeURI()

不会对本身属于URI的特殊字符进行编码,比如冒号、斜杠、问号、井号

decodeURI() 解码

encodeURIComponent()

对任何非标准字符编码

decodeURIComponnet()

eval()
严格模式下,外部访问不到eval()中创建的任何变量/函数。

Math

Math对象的属性
JavaScript高级程序设计 第4版(中文高清)扫描版

min() max()
确定一组数值中的最小/大值

Math.ceil()向上舍入为最接近的整数,
Math.floor()向下舍入
Math.round()四舍五入
Math.fround()方法返回数值最接近的单精度(32 位)浮点值表示。

console.log(Math.ceil(25.9)); // 26 
console.log(Math.ceil(25.5)); // 26 
console.log(Math.ceil(25.1)); // 26 
console.log(Math.round(25.9)); // 26 
console.log(Math.round(25.5)); // 26 
console.log(Math.round(25.1)); // 25 
console.log(Math.fround(0.4)); // 0.4000000059604645 
console.log(Math.fround(0.5)); // 0.5 
console.log(Math.fround(25.9)); // 25.899999618530273 
console.log(Math.floor(25.9)); // 25 
console.log(Math.floor(25.5)); // 25 
console.log(Math.floor(25.1)); // 25

random()

返回介于0 1之间的数,不包括0,1.
Math.floor(Math.random()*可能值的总数+第一个可能的数)

Math.abs()

6. 集合引用类型

6.1 Object类型

//Object构造函数
new Object()
//对象字面量
{ 
   }

属性一般是通过点语法来存取的
属性名包含空格,关键字,时使用 []访问属性

ES6-对象的扩展-Object.keys(),Object.values(),Object.entries()

Object.entries()

6.2 Array

详细介绍

6.2.1 创建数组

//Array构造函数
new Array()
let colors = new Array(20);
let colors = new Array("red", "blue", "green");

//在使用 Array 构造函数时,也可以省略 new 操作符。结果是一样的,比如:
let colors = Array(3); // 创建一个包含 3 个元素的数组
let names = Array("Greg"); // 创建一个只包含一个元素,即字符串"Greg"的数组

//数组字面量
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个元素的数组
let names = []; // 创建一个空数组
let values = [1,2,]; // 创建一个包含 2 个元素的数组

from()
将类数组对象转换为数组实例
参数:类数组对象,[映射函数],[指定映射函数中this 的值]

// 字符串会被拆分为单字符数组
console.log(Array.from("Matt")); // ["M", "a", "t", "t"] 
// 可以使用 from()将集合和映射转换为一个新数组
const m = new Map().set(1, 2) 
.set(3, 4); 
const s = new Set().add(1) 
.add(2) 
.add(3) 
.add(4); 
console.log(Array.from(m)); // [[1, 2], [3, 4]] 
console.log(Array.from(s)); // [1, 2, 3, 4] 
// Array.from()对现有数组执行浅复制
const a1 = [1, 2, 3, 4]; 
const a2 = Array.from(a1); 
console.log(a1); // [1, 2, 3, 4] 
alert(a1 === a2); // false 
// 可以使用任何可迭代对象
const iter = { 
 
*[Symbol.iterator]() { 
 
yield 1; 
yield 2; 
yield 3; 
yield 4; 
} 
}; 
console.log(Array.from(iter)); // [1, 2, 3, 4]
// arguments 对象可以被轻松地转换为数组
function getArgsArray() { 
 
return Array.from(arguments); 
} 
console.log(getArgsArray(1, 2, 3, 4)); // [1, 2, 3, 4] 
// from()也能转换带有必要属性的自定义对象
const arrayLikeObject = { 
 
0: 1, 
1: 2, 
2: 3, 
3: 4, 
length: 4 
}; 
console.log(Array.from(arrayLikeObject)); // [1, 2, 3, 4]

Array.from()还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,而无须像
调用 Array.from().map()那样先创建一个中间数组。还可以接收第三个可选参数,用于指定映射函
数中 this 的值。但这个重写的 this 值在箭头函数中不适用。

const a1 = [1, 2, 3, 4]; 
const a2 = Array.from(a1, x => x**2); 
const a3 = Array.from(a1, function(x) { 
return x**this.exponent}, { 
exponent: 2}); 
console.log(a2); // [1, 4, 9, 16] 
console.log(a3); // [1, 4, 9, 16]

Array.of()
可以把一组参数转换为数组。这个方法用于替代在 ES6之前常用的 Array.prototype. slice.call(arguments),一种异常笨拙的将 arguments 对象转换为数组的写法:
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
console.log(Array.of(undefined)); // [undefined]

6.2.2 数组空位

ES6 新增方法普遍将这些空位当成存在的元素,只不过值为 undefined:

const options = [,,,,,]; // 创建包含 5 个元素的数组
console.log(options.length); // 5 
console.log(options); // [,,,,,]
// map()会跳过空位置
console.log(options.map(() => 6)); // [6, undefined, undefined, undefined, 6] 
// join()视空位置为空字符串
console.log(options.join('-')); // "1----5"

检测数组

一个网页
instanceof

多个框架,多个全局执行环境
Array.isArray()

迭代器方法

原型方法:
keys()
返回索引迭代器

values()
返回数组元素的迭代器

entries()
返回索引/值对的迭代器

const a = ["foo", "bar", "baz", "qux"];
// 因为这些方法都返回迭代器,所以可以将它们的内容
// 通过Array.from()直接转换为数组实例
const aKeys = Array.from(a.keys());
const aValues = Array.from(a.values());
const aEntries = Array.from(a.entries());
console.log(aKeys); // [0, 1, 2, 3]
console.log(aValues); // ["foo", "bar", "baz", "qux"]
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]

使用ES6 的解构可以非常容易地在循环中拆分键/值对:

const a = ["foo", "bar", "baz", "qux"];
for (const [idx, element] of a.entries()) { 

alert(idx);
alert(element);
}

复制和填充

fill()

  • 可以向一个已有的数组中插入全部或部分相同的值。开始索引用于指定开始填充
    的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。负值索引从数组末尾开始计算。
    也可以将负索引想象成数组长度加上它得到的一个正索引:

copyWithin()

  • 会按照指定范围浅复制数组中的部分内容,然后将它们插入到指
    定索引开始的位置。开始索引和结束索引则与 fill()使用同样的计算方法:

转换

toString() ,分隔的字符串
valueOf() 数组本身
join() 参数:分隔符

栈方法

后进先出
数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个地方发生,即栈顶。

push() 推入
向数组末端添加项,返回修改后数组的长度

pop() 弹出
从数组末尾移除最后一项,返回移除的项

列队方法

先进先出
push()
shift() 移除数组中的第一项并返回该项

unshift() 在数组顶端添加任意项并返回,返回新数组的长度
pop()

重排序方法

reverse()
反向排序

sort()

调用toString()方法,比较得到的字符串,确定如何排序
接收比较函数为参数

比较函数接收两个参数,如果第一个参数应该排在第二个参数前面,就返回负值;如果两个参数相
等,就返回0;如果第一个参数应该排在第二个参数后面,就返回正值。

function compare(value1, value2) { 

if (value1 < value2) { 

return -1;
} else if (value1 > value2) { 

return 1;
} else { 

return 0;
}
}

如果数组的元素是数值,或者是其valueOf()方法返回数值的对象(如Date 对象),这个比较函
数还可以写得更简单,因为这时可以直接用第二个值减去第一个值:
function compare(value1, value2){

return value2 – value1;
}

操作方法

concat()

基于当前数组中的所有项创建一个新数组。
如参数是一个或多个数组,将数组中的每一项添加到结果数组中。如参数不是数组,值被简单的添加到结果数组的末尾。

//打平数组参数的行为可以重写
//Symbol.isConcatSpreadable
let colors=[1,2,3]
let newColors=[3,4]
let moreNewColors={ 

[Symbol.isConcatSpreadable]:true,
length:2,
0:5,
1:6
}
newColor[Symbol.isConcatSpreadable]=false
//强制不打平数组
let colors2=colors.concat(newColors)
//强制打平类数组对象
let colors3=colors.concat(moreNewColors)

slice()

截取数组
参数:[返回项的起始索引],[结束位置索引(不包括)]。
浅拷贝,不修改原数组
有负数,以数组长度加上负数 slice(-2,-1) slice(3,4) //length=5
结束位置小于开始位置,返回[]

splice()
向数组中插入项
参数:起始位置,要删除的项数,要插入的项
返回:被删除的元素

  • 删除:
  • 插入
  • 替换

搜索和位置方法

1.全等操作
indexOf()
参数:要查找的项,[查找起点位置的索引]
返回:要查找的元素在数组中的位置,如果没找到则返回1。

lastIndexOf()
没找到-1

includes()
返回布尔值,表示是否至少找到一个与指定元素匹配的项
2.断言函数
find()
返回第一个匹配的元素
这两个方法也都接收第二个可选的参数,
用于指定断言函数内部 this 的值。

findIndex()
返回第一个匹配元素的索引

迭代方法

参数:1.要在每项上运行的函数 2.[运行该函数的作用域对象,影响this指向]

函数的参数:1.数组项的值 2.该项在数组中的位置 3.数组本身

都不修改数组包含的值

every()

对数组中的每一项运行给定函数,该函数对每一项都返回true,则返回true

filter()

返回该函数会返回true的项组成的数组

forEach()

对数组每一项都运行传入的函数,没有返回值

map()

对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组

some()

任意一项返回true,则返回true

缩小方法 归并方法

迭代数组的所有项,构建一个最终的返回值。
参数:1.一个在每项上调用的函数 2.[作为缩小基础的初始值]

函数的参数:前一个值,当前值,项的索引,数组对象
这个函数返回的任何值都会作为第一个参数自动传给下一项,第一次迭代发生在数组的第二项上,第一个参数是数组的第一项,第二个参数是数组的第二项。

reduce()
reduceRight()

var value=[1,2,3];
var sum=value.reduce((pre,cur,index,arr)=>{ 

return pre+cur;
})

6.3 定型数组

目的是提升向原生库传输数据的效率

历史

  1. WebGL
  • 充分利用3D图形API,GUPL,以便渲染复杂图像
  • 图形驱动程序 API 通常不需要以 JavaScript 默认双精度浮点格式传递给它们的数值,而这恰恰是 JavaScript
    数组在内存中的格式。因此,每次 WebGL 与 JavaScript 运行时之间传递数组时,WebGL 绑定都需要在
    目标环境分配新数组,以其当前格式迭代数组,然后将数值转型为新数组中的适当格式,而这些要花费
    很多时间。
  1. 定型数组
    CanvasFloatArray。这是一个提供
    JavaScript 接口的、C 语言风格的浮点值数组。JavaScript 运行时使用这个类型可以分配、读取和写入数组。
    这个数组可以直接传给底层图形驱动程序 API,也可以直接从底层获取到。最终,CanvasFloatArray
    变成了 Float32Array,也就是今天定型数组中可用的第一个“类型”。

ArrayBuffer

ArrayBuffer()是一个普通的 JavaScript 构造函数,可用于在内存中分配特定数量的字节空间。

const buf = new ArrayBuffer(16); // 在内存中分配 16 字节
alert(buf.byteLength); // 16

ArrayBuffer 一经创建就不能再调整大小。不过,可以使用 slice()复制其全部或部分到一个新
实例中:
const buf1 = new ArrayBuffer(16);
const buf2 = buf1.slice(4, 12);
alert(buf2.byteLength); // 8
ArrayBuffer 某种程度上类似于 C++的 malloc(),但也有几个明显的区别。
 malloc()在分配失败时会返回一个 null 指针。ArrayBuffer 在分配失败时会抛出错误。
 malloc()可以利用虚拟内存,因此最大可分配尺寸只受可寻址系统内存限制。ArrayBuffer
分配的内存不能超过 Number.MAX_SAFE_INTEGER(253  1)字节。
 malloc()调用成功不会初始化实际的地址。声明 ArrayBuffer 则会将所有二进制位初始化
为 0。  通过 malloc()分配的堆内存除非调用 free()或程序退出,否则系统不能再使用。而通过声明
ArrayBuffer 分配的堆内存可以被当成垃圾回收,不用手动释放。
不能仅通过对 ArrayBuffer 的引用就读取或写入其内容。要读取或写入 ArrayBuffer,就必须
通过视图。视图有不同的类型,但引用的都是 ArrayBuffer 中存储的二进制数据。

6.3.3 DataView

第一种允许你读写 ArrayBuffer 的视图是DataView。这个视图专为文件 I/O 和网络 I/O 设计,其API 支持对缓冲数据的高度控制,但相比于其他类型的视图性能也差一些。DataView 对缓冲内容没有任何预设,也不能迭代。
必须在对已有的 ArrayBuffer 读取或写入时才能创建 DataView 实例。这个实例可以使用全部或部分 ArrayBuffer,且维护着对该缓冲实例的引用,以及视图在缓冲中开始的位置。

const buf = new ArrayBuffer(16); 
// DataView 默认使用整个 ArrayBuffer 
const fullDataView = new DataView(buf); 
alert(fullDataView.byteOffset); // 0 
alert(fullDataView.byteLength); // 16 
alert(fullDataView.buffer === buf); // true 
// 构造函数接收一个可选的字节偏移量和字节长度
// byteOffset=0 表示视图从缓冲起点开始
// byteLength=8 限制视图为前 8 个字节
const firstHalfDataView = new DataView(buf, 0, 8); 
alert(firstHalfDataView.byteOffset); // 0 
alert(firstHalfDataView.byteLength); // 8 
alert(firstHalfDataView.buffer === buf); // true 
// 如果不指定,则 DataView 会使用剩余的缓冲
// byteOffset=8 表示视图从缓冲的第 9 个字节开始
// byteLength 未指定,默认为剩余缓冲
const secondHalfDataView = new DataView(buf, 8); 
alert(secondHalfDataView.byteOffset); // 8
alert(secondHalfDataView.byteLength); // 8 
alert(secondHalfDataView.buffer === buf); // true

要通过 DataView 读取缓冲,还需要几个组件。
 首先是要读或写的字节偏移量。可以看成 DataView 中的某种“地址”。
 DataView 应该使用 ElementType 来实现 JavaScript 的 Number 类型到缓冲内二进制格式的转
换。
 最后是内存中值的字节序。默认为大端字节序。

  1. ElementType
    DataView 对存储在缓冲内的数据类型没有预设。它暴露的 API 强制开发者在读、写时指定一个
    ElementType,然后 DataView 就会忠实地为读、写而完成相应的转换。
    ECMAScript 6 支持 8 种不同的 ElementType(见下表)
    在这里插入图片描述
    DataView 为上表中的每种类型都暴露了 get 和 set 方法,这些方法使用 byteOffset(字节偏移
    量)定位要读取或写入值的位置。类型是可以互换使用的,如下例所示:
// 在内存中分配两个字节并声明一个 DataView 
const buf = new ArrayBuffer(2); 
const view = new DataView(buf); 
// 说明整个缓冲确实所有二进制位都是 0 
// 检查第一个和第二个字符
alert(view.getInt8(0)); // 0 
alert(view.getInt8(1)); // 0 
// 检查整个缓冲
alert(view.getInt16(0)); // 0 
// 将整个缓冲都设置为 1 
// 255 的二进制表示是 11111111(2^8 - 1)
view.setUint8(0, 255); 
// DataView 会自动将数据转换为特定的 ElementType 
// 255 的十六进制表示是 0xFF 
view.setUint8(1, 0xFF); 
// 现在,缓冲里都是 1 了
// 如果把它当成二补数的有符号整数,则应该是-1 
alert(view.getInt16(0)); // -1
  1. 字节序
    前面例子中的缓冲有意回避了字节序的问题。“字节序”指的是计算系统维护的一种字节顺序的约
    定。DataView 只支持两种约定:大端字节序和小端字节序。大端字节序也称为“网络字节序”,意思
    是最高有效位保存在第一个字节,而最低有效位保存在最后一个字节。小端字节序正好相反,即最低有
    效位保存在第一个字节,最高有效位保存在最后一个字节。
    JavaScript 运行时所在系统的原生字节序决定了如何读取或写入字节,但 DataView 并不遵守这
    个约定。对一段内存而言,DataView 是一个中立接口,它会遵循你指定的字节序。DataView 的所
    有 API 方法都以大端字节序作为默认值,但接收一个可选的布尔值参数,设置为 true 即可启用小端
    字节序。
    // 在内存中分配两个字节并声明一个 DataView
    const buf = new ArrayBuffer(2);
    const view = new DataView(buf);
    // 填充缓冲,让第一位和最后一位都是 1
    view.setUint8(0, 0x80); // 设置最左边的位等于 1
    view.setUint8(1, 0x01); // 设置最右边的位等于 1
    // 缓冲内容(为方便阅读,人为加了空格)
    // 0x8 0x0 0x0 0x1
    // 1000 0000 0000 0001
    // 按大端字节序读取 Uint16
    // 0x80 是高字节,0x01 是低字节
    // 0x8001 = 2^15 + 2^0 = 32768 + 1 = 32769
    alert(view.getUint16(0)); // 32769
    // 按小端字节序读取 Uint16
    // 0x01 是高字节,0x80 是低字节
    // 0x0180 = 2^8 + 2^7 = 256 + 128 = 384
    alert(view.getUint16(0, true)); // 384
    // 按大端字节序写入 Uint16
    view.setUint16(0, 0x0004);
    // 缓冲内容(为方便阅读,人为加了空格)
    // 0x0 0x0 0x0 0x4
    // 0000 0000 0000 0100
    alert(view.getUint8(0)); // 0
    alert(view.getUint8(1)); // 4
    // 按小端字节序写入 Uint16
    view.setUint16(0, 0x0002, true);
    // 缓冲内容(为方便阅读,人为加了空格)
    // 0x0 0x2 0x0 0x0
    // 0000 0010 0000 0000
    alert(view.getUint8(0)); // 2
    alert(view.getUint8(1)); // 0
  2. 边界情形
    DataView 完成读、写操作的前提是必须有充足的缓冲区,否则就会抛出 RangeError:
    const buf = new ArrayBuffer(6);
    const view = new DataView(buf);
    // 尝试读取部分超出缓冲范围的值
    view.getInt32(4);
    // RangeError
    // 尝试读取超出缓冲范围的值
    view.getInt32(8);
    // RangeError
    // 尝试读取超出缓冲范围的值
    view.getInt32(-1);
    // RangeError
    // 尝试写入超出缓冲范围的值
    view.setInt32(4, 123);
    // RangeError
    DataView 在写入缓冲里会尽最大努力把一个值转换为适当的类型,后备为 0。如果无法转换,则
    抛出错误:
    const buf = new ArrayBuffer(1);
    const view = new DataView(buf);
    view.setInt8(0, 1.5);
    alert(view.getInt8(0)); // 1
    view.setInt8(0, [4]);
    alert(view.getInt8(0)); // 4
    view.setInt8(0, ‘f’);
    alert(view.getInt8(0)); // 0
    view.setInt8(0, Symbol());
    // TypeError

6.3.4 定型数组

设计定型数组的目的就是提高与 WebGL 等原生库交换二进制数据的效率。由于定
型数组的二进制表示对操作系统而言是一种容易使用的格式,JavaScript 引擎可以重度优化算术运算、
按位运算和其他对定型数组的常见操作,因此使用它们速度极快。
创建定型数组的方式包括读取已有的缓冲、使用自有缓冲、填充可迭代结构,以及填充基于任意类
型的定型数组。另外,通过.from()和.of()也可以创建定型数组:

// 创建一个 12 字节的缓冲
const buf = new ArrayBuffer(12); 
// 创建一个引用该缓冲的 Int32Array 
const ints = new Int32Array(buf); 
// 这个定型数组知道自己的每个元素需要 4 字节
// 因此长度为 3 
alert(ints.length); // 3
// 创建一个长度为 6 的 Int32Array 
const ints2 = new Int32Array(6); 
// 每个数值使用 4 字节,因此 ArrayBuffer 是 24 字节
alert(ints2.length); // 6 
// 类似 DataView,定型数组也有一个指向关联缓冲的引用
alert(ints2.buffer.byteLength); // 24 
// 创建一个包含[2, 4, 6, 8]的 Int32Array 
const ints3 = new Int32Array([2, 4, 6, 8]); 
alert(ints3.length); // 4 
alert(ints3.buffer.byteLength); // 16 
alert(ints3[2]); // 6 
// 通过复制 ints3 的值创建一个 Int16Array 
const ints4 = new Int16Array(ints3); 
// 这个新类型数组会分配自己的缓冲
// 对应索引的每个值会相应地转换为新格式
alert(ints4.length); // 4 
alert(ints4.buffer.byteLength); // 8 
alert(ints4[2]); // 6 
// 基于普通数组来创建一个 Int16Array 
const ints5 = Int16Array.from([3, 5, 7, 9]); 
alert(ints5.length); // 4 
alert(ints5.buffer.byteLength); // 8 
alert(ints5[2]); // 7 
// 基于传入的参数创建一个 Float32Array 
const floats = Float32Array.of(3.14, 2.718, 1.618); 
alert(floats.length); // 3 
alert(floats.buffer.byteLength); // 12 
alert(floats[2]); // 1.6180000305175781 
定型数组的构造函数和实例都有一个 BYTES_PER_ELEMENT 属性,返回该类型数组中每个元素的大小:
alert(Int16Array.BYTES_PER_ELEMENT); // 2 
alert(Int32Array.BYTES_PER_ELEMENT); // 4 
const ints = new Int32Array(1), 
floats = new Float64Array(1); 
alert(ints.BYTES_PER_ELEMENT); // 4 
alert(floats.BYTES_PER_ELEMENT); // 8 
如果定型数组没有用任何值初始化,则其关联的缓冲会以 0 填充:
const ints = new Int32Array(4); 
alert(ints[0]); // 0 
alert(ints[1]); // 0 
alert(ints[2]); // 0 
alert(ints[3]); // 0 
  1. 定型数组行为
    从很多方面看,定型数组与普通数组都很相似。定型数组支持如下操作符、方法和属性:
     []
     copyWithin()
     entries()
     every()
     fill()
     filter()
     find()
     findIndex()
     forEach()
     indexOf()
     join()
     keys()
     lastIndexOf()
     length
     map()
     reduce()
     reduceRight()
     reverse()
     slice()
     some()
     sort()
     toLocaleString()
     toString()
     values()
    其中,返回新数组的方法也会返回包含同样元素类型(element type)的新定型数组:
    const ints = new Int16Array([1, 2, 3]);
    const doubleints = ints.map(x => 2*x);
    alert(doubleints instanceof Int16Array); // true
    定型数组有一个 Symbol.iterator 符号属性,因此可以通过 for…of 循环和扩展操作符来操作:
    const ints = new Int16Array([1, 2, 3]);
    for (const int of ints) {

    alert(int);
    }
    // 1
    // 2
    // 3
    alert(Math.max(…ints)); // 3
  2. 合并、复制和修改定型数组
    定型数组同样使用数组缓冲来存储数据,而数组缓冲无法调整大小。因此,下列方法不适用于定型
    数组:
     concat()
     pop()
     push()
     shift()
     splice()
     unshift()
    不过,定型数组也提供了两个新方法,可以快速向外或向内复制数据:set()和 subarray()。
    set()从提供的数组或定型数组中把值复制到当前定型数组中指定的索引位置:
    // 创建长度为 8 的 int16 数组
    const container = new Int16Array(8);
    // 把定型数组复制为前 4 个值
    // 偏移量默认为索引 0
    container.set(Int8Array.of(1, 2, 3, 4));
    console.log(container); // [1,2,3,4,0,0,0,0]
    // 把普通数组复制为后 4 个值
    // 偏移量 4 表示从索引 4 开始插入
    container.set([5,6,7,8], 4);
    console.log(container); // [1,2,3,4,5,6,7,8]
    // 溢出会抛出错误
    container.set([5,6,7,8], 7);
    // RangeError
    subarray()执行与 set()相反的操作,它会基于从原始定型数组中复制的值返回一个新定型数组。
    复制值时的开始索引和结束索引是可选的:
    const source = Int16Array.of(2, 4, 6, 8);
    // 把整个数组复制为一个同类型的新数组
    const fullCopy = source.subarray();
    console.log(fullCopy); // [2, 4, 6, 8]
    // 从索引 2 开始复制数组
    const halfCopy = source.subarray(2);
    console.log(halfCopy); // [6, 8]
    // 从索引 1 开始复制到索引 3
    const partialCopy = source.subarray(1, 3);
    console.log(partialCopy); // [4, 6]
    定型数组没有原生的拼接能力,但使用定型数组 API 提供的很多工具可以手动构建:
    // 第一个参数是应该返回的数组类型
    // 其余参数是应该拼接在一起的定型数组
    function typedArrayConcat(typedArrayConstructor, …typedArrays) {

    // 计算所有数组中包含的元素总数
    const numElements = typedArrays.reduce((x,y) => (x.length || x) + y.length);
    // 按照提供的类型创建一个数组,为所有元素留出空间
    const resultArray = new typedArrayConstructor(numElements);
    // 依次转移数组
    let currentOffset = 0;
    typedArrays.map(x => {

    resultArray.set(x, currentOffset);
    currentOffset += x.length;
    });
    return resultArray;
    }
    const concatArray = typedArrayConcat(Int32Array,
    Int8Array.of(1, 2, 3),
    Int16Array.of(4, 5, 6),
    Float32Array.of(7, 8, 9));
    console.log(concatArray); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
    console.log(concatArray instanceof Int32Array); // true
    // 长度为 2 的有符号整数数组
    // 每个索引保存一个二补数形式的有符号整数
    // 范围是-128(-1 * 27)~127(27 – 1)
    const ints = new Int8Array(2);
    // 长度为 2 的无符号整数数组
    // 每个索引保存一个无符号整数
    // 范围是 0~255(2^7 – 1)
    const unsignedInts = new Uint8Array(2);
    // 上溢的位不会影响相邻索引
    // 索引只取最低有效位上的 8 位
    unsignedInts[1] = 256; // 0x100
    console.log(unsignedInts); // [0, 0]
    unsignedInts[1] = 511; // 0x1FF
    console.log(unsignedInts); // [0, 255]
    // 下溢的位会被转换为其无符号的等价值
    // 0xFF 是以二补数形式表示的-1(截取到 8 位),
    // 但 255 是一个无符号整数
    unsignedInts[1] = -1 // 0xFF (truncated to 8 bits)
    console.log(unsignedInts); // [0, 255]
    // 上溢自动变成二补数形式
    // 0x80 是无符号整数的 128,是二补数形式的-128
    ints[1] = 128; // 0x80
    console.log(ints); // [0, -128]
    // 下溢自动变成二补数形式
    // 0xFF 是无符号整数的 255,是二补数形式的-1
    ints[1] = 255; // 0xFF
    console.log(ints); // [0, -1]
    除了 8 种元素类型,还有一种“夹板”数组类型:Uint8ClampedArray,不允许任何方向溢出。
    超出最大值 255 的值会被向下舍入为 255,而小于最小值 0 的值会被向上舍入为 0。
    const clampedInts = new Uint8ClampedArray([-1, 0, 255, 256]);
    console.log(clampedInts); // [0, 0, 255, 255]
    按照 JavaScript 之父 Brendan Eich 的说法:“Uint8ClampedArray 完全是 HTML5canvas 元素的
    历史留存。除非真的做跟 canvas 相关的开发,否则不要使用它。”

6.4 Map

键/值 储存
Object:只能用数值,字符串,符号做键
Map:可使用任何js数据类型做键

API

创建空映射
new Map()
可传入一个可迭代对象,需包含键/值对的数组。

//使用嵌套数组初始化映射
const m1=new Map([
["key","val"],
["key","val"],
])
//可以通过 size 属性获取映射中的键/值对的数量
alert(m1.size); // 3
//使用自定义迭代器初始化映射
const m2=new Map([
[Symbol.iterator]:function*(){ 

yield ["key","val"];
yield ["key","val"];
}
])
// 映射期待的键/值对,无论是否提供
const m3 = new Map([[]]); 
alert(m3.has(undefined)); // true 
alert(m3.get(undefined)); // undefined
//使用set()方法添加键/值对
m1.set("an","cc")
//使用get(),has()查询
m1.has("na")
m1.get("na")
//delete(),clear()删除值
m.delete("firstName"); // 只删除这一个键/值对
m1.clear()	//清除这个映射实例中的所有键/值对
//set()方法返回映射实例,因此可以把多个操作连缀起来,包括初始化声明:
const m = new Map().set("key1", "val1"); 
m.set("key2", "val2") 
.set("key3", "val3"); 
alert(m.size); // 3

顺序与迭代

与Object 类型的一个主要差异是,Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执
行迭代操作。
映射实例可以提供一个迭代器(Iterator),能以插入顺序生成[key, value]形式的数组。可以
通过 entries()方法(或者 Symbol.iterator 属性,它引用 entries())取得这个迭代器:

const m = new Map([ 
["key1", "val1"], 
["key2", "val2"], 
["key3", "val3"] 
]); 
alert(m.entries === m[Symbol.iterator]); // true 
for (let pair of m.entries()) { 
 
alert(pair); 
} 
// [key1,val1] 
// [key2,val2] 
// [key3,val3] 
for (let pair of m[Symbol.iterator]()) { 
 
alert(pair); 
} 
// [key1,val1] 
// [key2,val2] 
// [key3,val3] 
因为 entries()是默认迭代器,所以可以直接对映射实例使用扩展操作,把映射转换为数组:
const m = new Map([ 
["key1", "val1"], 
["key2", "val2"], 
["key3", "val3"] 
]); 
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]] 
如果不使用迭代器,而是使用回调方式,则可以调用映射的 forEach(callback, opt_thisArg)
方法并传入回调,依次迭代每个键/值对。传入的回调接收可选的第二个参数,这个参数用于重写回调
内部 this 的值:
const m = new Map([ 
["key1", "val1"], 
["key2", "val2"], 
["key3", "val3"] 
]); 
m.forEach((val, key) => alert(`${ 
key} -> ${ 
val}`)); 
// key1 -> val1 
// key2 -> val2 
// key3 -> val3 
keys()values()分别返回以插入顺序生成键和值的迭代器:
const m = new Map([ 
["key1", "val1"], 
["key2", "val2"], 
["key3", "val3"] 
]); 
for (let key of m.keys()) { 
 
alert(key); 
} 
// key1 
// key2 
// key3 
for (let key of m.values()) { 
 
alert(key); 
} 
// value1 
// value2 
// value3 
键和值在迭代器遍历时是可以修改的,但映射内部的引用则无法修改。当然,这并不妨碍修改作为
键或值的对象内部的属性,因为这样并不影响它们在映射实例中的身份:
const m1 = new Map([ 
["key1", "val1"] 
]); 
// 作为键的字符串原始值是不能修改的
for (let key of m1.keys()) { 
 
key = "newKey"; 
alert(key); // newKey 
alert(m1.get("key1")); // val1 
} 
const keyObj = { 
id: 1}; 
const m = new Map([ 
[keyObj, "val1"] 
]); 
// 修改了作为键的对象的属性,但对象在映射内部仍然引用相同的值
for (let key of m.keys()) { 
 
key.id = "newKey"; 
alert(key); // {id: "newKey"} 
alert(m.get(keyObj)); // val1 
} 
alert(keyObj); // {id: "newKey"}

6.4.3 选择 Object 还是 Map

对于多数 Web 开发任务来说,选择 Object 还是 Map 只是个人偏好问题,影响不大。不过,对于
在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。

  1. 内存占用
    Object 和 Map 的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量
    都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。
    不同浏览器的情况不同,但给定固定大小的内存,Map 大约可以比 Object 多存储 50%的键/值对。
  2. 插入性能
    向 Object 和 Map 中插入新键/值对的消耗大致相当,不过插入 Map 在所有浏览器中一般会稍微快
    一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操
    作,那么显然 Map 的性能更佳。
  3. 查找速度
    与插入不同,从大型 Object 和 Map 中查找键/值对的性能差异极小,但如果只包含少量键/值对,
    则 Object 有时候速度更快。在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏
    览器引擎可以进行优化,在内存中使用更高效的布局。这对 Map 来说是不可能的。对这两个类型而言,
    查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选
    择 Object 更好一些。
  4. 删除性能
    使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,
    出现了一些伪删除对象属性的操作,包括把属性值设置为 undefined 或 null。但很多时候,这都是一
    种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Map 的 delete()操作都比插入和查找更快。
    如果代码涉及大量删除操作,那么毫无疑问应该选择 Map。

6.5 WeakMap

const wm = new WeakMap();
弱映射中的键只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置键会抛出
TypeError。值的类型没有限制。

6.6 Set

集合
加强的Map

API

const m = new Set();
如果想在创建的同时初始化实例,则可以给 Set 构造函数传入一个可迭代对象,其中需要包含插入
到新集合实例中的元素:
// 使用数组初始化集合
const s1 = new Set([“val1”, “val2”, “val3”]);
alert(s1.size); // 3
// 使用自定义迭代器初始化集合
const s2 = new Set({

[Symbol.iterator]: function*() {

yield “val1”;
yield “val2”;
yield “val3”;
}
});
alert(s2.size); // 3

const s = new Set(); 
alert(s.has("Matt")); // false 
alert(s.size); // 0 
//add()增加值 返回集合的实例,所以可以将多个添加操作连缀起来,包括初始化:
s.add("Matt") 
.add("Frisbie"); 
alert(s.has("Matt")); // true 
//size 取得元素数量
alert(s.size); // 2 
s.delete("Matt"); 
//has()查询
alert(s.has("Matt")); // false 
alert(s.has("Frisbie")); // true 
alert(s.size); // 1 
//delete()和 clear()删除元素:
s.clear(); // 销毁集合实例中的所有值
alert(s.has("Matt")); // false 
alert(s.has("Frisbie")); // false 
alert(s.size); // 0

6.6.2 顺序与迭代

Set 会维护值插入时的顺序,因此支持按顺序迭代。
集合实例可以提供一个迭代器(Iterator),能以插入顺序生成集合内容。可以通过 values()方
法及其别名方法 keys()(或者 Symbol.iterator 属性,它引用 values())取得这个迭代器:
const s = new Set([“val1”, “val2”, “val3”]);
alert(s.values === s[Symbol.iterator]); // true
alert(s.keys === s[Symbol.iterator]); // true
for (let value of s.values()) {

alert(value);
}
// val1
// val2
// val3
for (let value of sSymbol.iterator) {

alert(value);
}
// val1
// val2
// val3
因为 values()是默认迭代器,所以可以直接对集合实例使用扩展操作,把集合转换为数组:
const s = new Set([“val1”, “val2”, “val3”]);
console.log([…s]); // [“val1”, “val2”, “val3”]
集合的 entries()方法返回一个迭代器,可以按照插入顺序产生包含两个元素的数组,这两个元
素是集合中每个值的重复出现:
const s = new Set([“val1”, “val2”, “val3”]);
for (let pair of s.entries()) {

console.log(pair);
}
// [“val1”, “val1”]
// [“val2”, “val2”]
// [“val3”, “val3”]
如果不使用迭代器,而是使用回调方式,则可以调用集合的 forEach()方法并传入回调,依次迭
代每个键/值对。传入的回调接收可选的第二个参数,这个参数用于重写回调内部 this 的值:
const s = new Set([“val1”, “val2”, “val3”]);
s.forEach((val, dupVal) => alert(${val} -> ${dupVal}));
// val1 -> val1
// val2 -> val2
// val3 -> val3
修改集合中值的属性不会影响其作为集合值的身份:
const s1 = new Set([“val1”]);
// 字符串原始值作为值不会被修改
for (let value of s1.values()) {

alert(value); // newVal
alert(s1.has(“val1”)); // true
}
const valObj = {id: 1};
const s2 = new Set([valObj]);
// 修改值对象的属性,但对象仍然存在于集合中
for (let value of s2.values()) {

value.id = “newVal”;
alert(value); // {id: “newVal”}
alert(s2.has(valObj)); // true
}
alert(valObj); // {id: “newVal”}

7. 迭代器与生成器

迭代:按顺序反复多次执行一段程序

7.1理解迭代

计数循环就是一种最简单的迭代:
for (let i = 1; i <= 10; ++i) {

console.log(i);
}
循环是迭代机制的基础,这是因为它可以指定迭代的次数,以及每次迭代要执行什么操作。每次循
环都会在下一次迭代开始之前完成,而每次迭代的顺序都是事先定义好的。
迭代会在一个有序集合上进行。(“有序”可以理解为集合中所有项都可以按照既定的顺序被遍历
到,特别是开始和结束项有明确的定义。)数组是 JavaScript 中有序集合的最典型例子。

for

forEach
这个方法解决了单独记录索引和通过数组对象取得值的问题。不过,没有办法标识迭代何时终止。
因此这个方法只适用于数组,而且回调结构也比较笨拙。

7.2 迭代器模式

可迭代对象是一种抽象的说法。基本上,可以把可迭代对象理解成数组或集合这样的集合类型的对
象。它们包含的元素都是有限的,而且都具有无歧义的遍历顺序:
// 数组的元素是有限的
// 递增索引可以按序访问每个元素
let arr = [3, 1, 4];
// 集合的元素是有限的
// 可以按插入顺序访问每个元素
let set = new Set().add(3).add(1).add(4);
不过,可迭代对象不一定是集合对象,也可以是仅仅具有类似数组行为的其他数据结构,比如本章
开头提到的计数循环。该循环中生成的值是暂时性的,但循环本身是在执行迭代。计数循环和数组都具
有可迭代对象的行为。

可迭代协议

实现Iterable 接口(可迭代协议)要求同时具备两种能力:支持迭代的自我识别能力和创建实现Iterator 接口的对象的能力。在ECMAScript 中,这意味着必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的Symbol.iterator 作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。
很多内置类型都实现了Iterable 接口:
 字符串
 数组
 映射
 集合
 arguments 对象
 NodeList 等DOM 集合类型

检查是否存在默认迭代器属性可以暴露这个工厂函数:

let num = 1;
let obj = { 
};
// 这两种类型没有实现迭代器工厂函数
console.log(num[Symbol.iterator]); // undefined
console.log(obj[Symbol.iterator]); // undefined
let str = 'abc'; 
let arr = ['a', 'b', 'c']; 
let map = new Map().set('a', 1).set('b', 2).set('c', 3); 
let set = new Set().add('a').add('b').add('c'); 
let els = document.querySelectorAll('div'); 
// 这些类型都实现了迭代器工厂函数
console.log(str[Symbol.iterator]); // f values() { [native code] } 
console.log(arr[Symbol.iterator]); // f values() { [native code] } 
console.log(map[Symbol.iterator]); // f values() { [native code] } 
console.log(set[Symbol.iterator]); // f values() { [native code] } 
console.log(els[Symbol.iterator]); // f values() { [native code] } 
// 调用这个工厂函数会生成一个迭代器
console.log(str[Symbol.iterator]()); // StringIterator {} 
console.log(arr[Symbol.iterator]()); // ArrayIterator {} 
console.log(map[Symbol.iterator]()); // MapIterator {} 
console.log(set[Symbol.iterator]()); // SetIterator {} 
console.log(els[Symbol.iterator]()); // ArrayIterator {}

接收可迭代对象的原生语言特性包括:
 for-of 循环
 数组解构
 扩展操作符
 Array.from()
 创建集合
 创建映射
 Promise.all()接收由期约组成的可迭代对象
 Promise.race()接收由期约组成的可迭代对象
 yield*操作符,在生成器中使用

7.3 生成器

7.3.1 生成器基础

生成器的形式是一个函数,函数名称前面加一个星号()表示它是一个生成器。只要是可以定义
函数的地方,就可以定义生成器。
// 生成器函数声明
function
generatorFn() {}

7.3.2 通过 yield 中断执行

8. 面向对象的程序设计

属性类型

内部 [[]]

数据属性
  • [[Configuralbe]] 能否通过delete删除属性重新定义,修改属性特性,把属性修改为访问器属性
  • [[Enumerable]] 能否通过fror-in循环
  • [[[Writable]] 能否修改属性值
  • [[Value]]

修改属性默认特性:
object.defineProperty(属性所在对象,属性名,描述符对象)

var person={ 
}
Object.defineProperty(person,"name",{ 

configurable:false,
writable:false,
value:"nn"
})
delete person.ff

访问器属性

getter 读取访问器属性
setter 写入访问器属性

  • [[Configuable]]
  • [[Enumerable]]
  • [[Get]]
  • [[Set]]
var book={ 

_year:2004,
edition:1
};
Object.defineProperty(book,"year",{ 

get:function(){ 

return this._year;
},
set:function(value){ 

if(value>2004){ 

this._year=value;
this.edition +=value-2004;
}
}
})

定义多个属性

var book={ 
}
Object.defineProperties(book,{ 

_year:{ 

value:22
},
year:{ 

get:()=>{ 
}
}
})

读取属性的特性

var book={ 
}
Object.defineProperties(book,{ 

_year:{ 

value:22
},
year:{ 

get:()=>{ 
}
}
})
Object.getOwnPropertyDescriptor(book,"_year")

创建对象

工厂模式

function createPerson(name,job){ 

var o-new Object();
o.name=name;
o.job=job;
return o;
}

构造函数模式

function Person(name){ 

this.name=name;
this.sayName=function(){ 

alert(this.name)
}
}
var person1=new Person("cjr")
var person2=new Person("cjr")
person1.sayName==person2.sayName	//false

new

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(this指向这个新对象)
  • 执行构造函数中的代码(为这个新对象添加属性)
  • 返回新对象

实例的constructor(构造函数)属性
person.constructor==person

问题:

没定义一个函数就实例化一个对象,
创建两个完成相同任务的Function实例没有必要,this对象存在,没必要把函数绑在特定的对象上。

function Person(name){ 

this.name=name;
//sayName包含一个指向函数的指针
this.sayName=sayName
}
//将函数定义转移到外面
//全局函数,实际上只被某个对象调用,???
function sayName=function(){ 

alert(this.name)
}

原型对象

每个函数都有一个prototype(原型)属性,是一个指针,指向一个对象(包含可以由特定类型的所有实例共享的属性,方法)

理解

函数都有一个prototype属性,指向函数的原型对象。
所有原型对象都有constructor构造函数属性,这个属性包含指向prototype属性所在函数的指针。
可为原型对象添加其他属性方法。

Person.prototype.constructor==Person

实例内部包含一个指针指向构造函数的原型对象。[[Prototype]] _proto_

Person.prototype.isPrototypeOf(person1);	//true
Object.getPrototypeOf(person1)==Person.prototype;	//true

属性查找过程:实例–原型
·
hasOwnProperty()
是否是实例属性

in
in操作符会在能通过对象访问给定属性时返回true,无论属性在原型/实例。

//给定属性是原型中的属性
function hasPropertypeProperty(object,name){ 

return !object.hasOwnProperty(name) && (name in object)
}

for-in
返回所有能通过对象访问,可枚举的属性,包含原型和实例。

function O(){ 

}
O.prototype={ 

name:"cc"
}
var o=new O();
for(var k in o){ 

console.log(k)
}

Object.keys()
获取对象上全部可枚举的实例属性

原型语法

//一、
O.prototype.name="cc"
//二、
O.prototype={ 

//会导致 可枚举
constructor:O,
name:"cc"
}
//三、
Object.defineProperty(O.prototype,"constructor",{ 

enumerable:false,
value:O
})

将O.prototype设置为一个新对象。constructor属性不再指向O
创建一个函数,会同时创建它的prototype对象,这个对象自动获得constructor属性。
完全重写了prototype对象,

缺点

  • 省略了为构造函数传递初始化参数
  • 对于引用类型的属性,会使实例共享一份数据,
function O(){ 
}
O.prototype={ 

friends:[1,2]
}
var o1=new O();
var o2=new O();
o1.friends.push(3);
console.log(o2.friends)

组合使用构造函数模式和原型模式

构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
极大限度的节省内存。

function O(name){ 

this.name=name;
this.firends=[1,2];
}
O.prototype={ 

constructor:O,
sayName:()=>{ 
}
}

动态原型模式

把全部信息封装在构造函数中,
不能用字面量重写原型, 如在已创建实例的情况下重写原型,会切断实例与原型之间的联系

function O(name){ 

this.name=name;
this.firends=[1,2];
//这段代码仅在初始化函数时执行,对原型的修改会在所有实例中反应。
if(typeof this.sayName != function){ 

O.prototype.sayName={ 
}
}
}

寄生构造函数模式 P180

稳妥构造函数模式

继承

依靠原型链实现继承

原型链

每个构造函数都有一个原型对象
原型对象都包含一个指向构造函数的指针
实例都包含一个指向原型对象的内部指针

如让原型对象等于另一个类型的实例,此时的原型对象将包含指向另一个原型对象的指针。

原型和实例的关系
只要是原型链中出现过的原型,都是该原型链所派生实例的原型
instanceof
isPrototypeOf()

给原型添加方法的代码一定要放在替换原型的语句之后,
不能使用字面量创建原型方法,会重写原型链
问题
引用类型
传参

借用构造函数

伪造对象,经典继承
子类构造函数内部调用超类构造函数

function SuperType(){ 

this.colors=[1,2]
}
function Subtype(){ 

//继承SuperType
//在SubType对象上执行SuperType()函数中所有的初始化代码
SuperType.call(this)
}
var ins=new SubType();
isn.clors.push(3)	//[1,2,3,]
var ins2=new SubType();
isn.clors	[1,2]

问题
方法都在构造函数中定义,无法复用

组合模式

9. 代理与反射

10. 函数

详细介绍

10.1 箭头函数

10.3 理解参数

10.7 函数声明与函数表达式

JavaScript 引擎在任何代码执行之前,会先读取函数声明,并在执行上下文中
生成函数定义。而函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义。来看
下面的例子:
// 没问题
console.log(sum(10, 10));
function sum(num1, num2) {

return num1 + num2;
}
以上代码可以正常运行,因为函数声明会在任何代码执行之前先被读取并添加到执行上下文。这个
过程叫作函数声明提升(function declaration hoisting)。在执行代码时,JavaScript 引擎会先执行一遍扫描,
把发现的函数声明提升到源代码树的顶部。因此即使函数定义出现在调用它们的代码之后,引擎也会把
函数声明提升到顶部。如果把前面代码中的函数声明改为等价的函数表达式,那么执行的时候就会出错:
// 会出错
console.log(sum(10, 10));
let sum = function(num1, num2) {

return num1 + num2;
};
上面的代码之所以会出错,是因为这个函数定义包含在一个变量初始化语句中,而不是函数声明中。
这意味着代码如果没有执行到加粗的那一行,那么执行上下文中就没有函数的定义,所以上面的代码会
出错。这

sayHI()
let condition=true;
if(condition){ 

function sayHI(){ 
console.log(1)}
}else{ 

function sayHI(){ 
console.log(13)}
}

在不同浏览器中可能会有不同的解释
用函数表达式则不会有问题

递归

function fac(num){ 

if(num<=1){ 

return 1
}else{ 

return num*fac(num-1)
}
}
var ano=fac;
fac=null;
ano(4)		//err

arguments.callee指向正在执行函数的指针

严格模式下,使用命名函数达到相同的效果
创建名为f()的明明函数表达式,赋值给fzc,即便把函数赋值给一个变量,函数名依然有效。

var fac=(function f(num){ 

if(num<=1){ 

}else{ 

return num*f(num-1)
}
})

闭包

有权访问另一个函数作用域中变量的函数。
一个函数内部创建另一个函数。
内部函数的作用域链包含了外部函数的作用域

某个函数第一次调用时,会创建一个执行环境(execution context)及相应的作用域链,并把作用域链赋值给一个特殊的内部变量[[Scope]].使用this,arguments和其他命名来初始化函数的活动对象。

自身的作用域排在第一位,外部函数的作用域始终排在第二位,…,直至终点全局执行环境。
函数执行完毕,局部活动对象就会被销毁,内存中仅保存全局作用域。

闭包
函数内部定义的函数会将包含函数(外部函数)的活动对象添加到它的作用域链中。
外部函数执行完毕,其活动对象也不会被销毁,因匿名函数的作用域链仍然在引用这个活动对象,
外部函数返回后,其执行环境的作用域链会别销毁,但他的活动对象仍然留在内存中,直到匿名函数被销毁。null
闭包会导致占用更多的内存。

闭包与变量

闭包只能取到所包含函数中任何变量的最后一个值。闭包包含的是整个变量对象。

function creacte(){ 

var result =[]
for(var i=0;i<3;i++){ 

result[i]=function(){ 

return i}
}
return result
}
creacte(3)[0]()	

每个函数的作用域链中保存着外部函数的活动对象,引用的都是同一个对象i.

function creacte(){ 

var result =[]
for(var i=0;i<3;i++){ 

result[i]=function(n){ 

return function(){ 

return n
}
}(i)
}
return result
}
creacte(3)[0]()	

this对象

基于函数的执行环境绑定的:
全局函数:this=window
作为某个对象的方法调用:this=对象
匿名函数的执行环境具有全局性:通常指向window

var name="this";
var obj={ 

name:"obj",
getName:function(){ 

var that=this;
return function (){ 

return this.name
}
}
}
obj.getName()()

匿名函数无法取得外部函数的this对象?
函数调用时,多动对象自动取得两个特殊对象:this,arguments.内部函数搜索这两个对象时,只会搜索到其活动对象为止,永远不可能直接访问外部函数中的这令个变量。
this保存在一个闭包可访问的变量里。

内存泄漏

function ass(){ 

}

模仿块级作用域

(function(){ 

//
})()

匿名函数中定义的任何变量,都会在执行结束时被销毁。

在全局作用域中用于函数外部,限制向全局作用域添加过多的变量和函数。避免命名冲突

(function (){ 

//
})()

创建私有作用域,每个开发者可创建自己的作用域,不必担心搞乱全局作用域
可减少闭包占用内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可销毁作用域链。

私有变量

任何函数中定义的变量
利用闭包可创建访问私有变量的特权方法
隐藏那些不该直接被修改的数据

function Obj(){ 

var name=10;
this.getName=function (){ 

return name;
}
}

静态私有变量

模块模式

单例:只有一个实例对象
为单例创建私有变量和特权方法

11. 期约与异步函数

promise
async await

11.1 异步编程

回调地狱

11.2 promise

11.2.2 期约基础

ECMAScript 6 新增的引用类型Promise,可以通过new 操作符来实例化。创建新期约时需要传入
执行器(executor)函数作为参数(后面马上会介绍),下面的例子使用了一个空函数对象来应付一下解释器:
let p = new Promise(() => {});
setTimeout(console.log, 0, p); // Promise

期约状态

 待定(pending)
 兑现(fulfilled,有时候也称为“解决”,resolved)
 拒绝(rejected)
待定(pending)是期约的最初始状态。在待定状态下,期约可以落定(settled)为代表成功的兑现(fulfilled)状态,或者代表失败的拒绝(rejected)状态。无论落定为哪种状态都是不可逆的。只要从待定转换为兑现或拒绝,期约的状态就不再改变。而且,也不能保证期约必然会脱离待定状态。因此,组织合理的代码无论期约解决(resolve)还是拒绝(reject),甚至永远处于待定(pending)状态,都应该具有恰当的行为。

解决值、拒绝理由及期约用例

为了支持这两种用例,每个期约只要状态切换为兑现,就会有一个私有的内部值(value)。类似地,
每个期约只要状态切换为拒绝,就会有一个私有的内部理由(reason)。无论是值还是理由,都是包含原
始值或对象的不可修改的引用。二者都是可选的,而且默认值为undefined。在期约到达某个落定状
态时执行的异步代码始终会收到这个值或理由。

通过执行函数控制期约状态

控制期约状态的转换是通过调用它的两个函数参数实现的。这两个函数参数通常都命名为resolve()和reject()。调用resolve()会把状态切换为兑现,调用reject()会把状态切换为拒绝。另外,调用reject()也会抛出错误无论resolve()和reject()中的哪个被调用,状态转换都不可撤销了。于是继续修改状态会静默失败

为避免期约卡在待定状态,可以添加一个定时退出功能。比如,可以通过setTimeout 设置一个10 秒钟后无论如何都会拒绝期约的回调:
let p = new Promise((resolve, reject) => {

setTimeout(reject, 10000); // 10 秒后调用reject()
// 执行函数的逻辑
});
setTimeout(console.log, 0, p); // Promise
setTimeout(console.log, 11000, p); // 11 秒后再检查状态
// (After 10 seconds) Uncaught error
// (After 11 seconds) Promise
因为期约的状态只能改变一次,所以这里的超时拒绝逻辑中可以放心地设置让期约处于待定状态的
最长时间。如果执行器中的代码在超时之前已经解决或拒绝,那么超时回调再尝试拒绝也会静默失败。

Promise.resolve()

期约并非一开始就必须处于待定状态,然后通过执行器函数才能转换为落定状态。通过调用
Promise.resolve()静态方法,可以实例化一个解决的期约。下面两个期约实例实际上是一样的:
let p1 = new Promise((resolve, reject) => resolve());
let p2 = Promise.resolve();
这个解决的期约的值对应着传给Promise.resolve()的第一个参数。使用这个静态方法,实际上
可以把任何值都转换为一个期约:
setTimeout(console.log, 0, Promise.resolve());
// Promise : undefined
setTimeout(console.log, 0, Promise.resolve(3));
// Promise : 3
// 多余的参数会忽略
setTimeout(console.log, 0, Promise.resolve(4, 5, 6));
// Promise : 4

Promise.reject()

与Promise.resolve()类似,Promise.reject()会实例化一个拒绝的期约并抛出一个异步错误
(这个错误不能通过try/catch 捕获,而只能通过拒绝处理程序捕获)。

11.2.3 期约的实例方法

实现Thenable 接口

在ECMAScript 暴露的异步结构中,任何对象都有一个then()方法。这个方法被认为实现了
Thenable 接口。下面的例子展示了实现这一接口的最简单的类:
class MyThenable {

then() {}
}
ECMAScript 的Promise 类型实现了Thenable 接口。这个简化的接口跟TypeScript 或其他包中的
接口或类型定义不同,它们都设定了Thenable 接口更具体的形式。

romise.prototype.then()

Promise.prototype.then()是为期约实例添加处理程序的主要方法

Promise.prototype.catch()

Promise.prototype.catch()方法用于给期约添加拒绝处理程序。这个方法只接收一个参数:
onRejected 处理程序。事实上,这个方法就是一个语法糖,调用它就相当于调用Promise.prototype.
then(null, onRejected)。

Promise.prototype.finally()

Promise.prototype.finally()方法用于给期约添加onFinally 处理程序,这个处理程序在期
约转换为解决或拒绝状态时都会执行。这个方法可以避免onResolved 和onRejected 处理程序中出
现冗余代码。但onFinally 处理程序没有办法知道期约的状态是解决还是拒绝,所以这个方法主要用
于添加清理代码。

 Promise.all()

Promise.all()静态方法创建的期约会在一组期约全部解决之后再解决。这个静态方法接收一个
可迭代对象,返回一个新期约:

11.3 异步函数

sync/await
这个期约在超时之后会解决为一个值:
let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
这个期约在1000 毫秒之后解决为数值3。如果程序中的其他代码要在这个值可用时访问它,则需要
写一个解决处理程序:
let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
p.then((x) => console.log(x)); // 3
这其实是很不方便的,因为其他代码都必须塞到期约处理程序中。不过可以把处理程序定义为一个
函数:
function handler(x) { console.log(x); }
let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
p.then(handler); // 3
这个改进其实也不大。这是因为任何需要访问这个期约所产生值的代码,都需要以处理程序的形式
来接收这个值。也就是说,代码照样还是要放到处理程序里。ES8 为此提供了async/await 关键字。

2. await

因为异步函数主要针对不会马上完成的任务,所以自然需要一种暂停和恢复执行的能力。使用await
关键字可以暂停异步函数代码的执行,等待期约解决。来看下面这个本章开始就出现过的例子:
let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
p.then((x) => console.log(x)); // 3
使用async/await 可以写成这样:
async function foo() {

let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
console.log(await p);
}
foo();
// 3
注意,await 关键字会暂停执行异步函数后面的代码,让出JavaScript 运行时的执行线程。这个行
为与生成器函数中的yield 关键字是一样的。await 关键字同样是尝试“解包”对象的值,然后将这
个值传给表达式,再异步恢复异步函数的执行。

12. BOM

window对象

在这里插入图片描述

表示浏览器的一个实例。

  • 通过js访问浏览器的一个接口
  • ES规定的全局对象

全局作用域

全局变量不能通过delete删除,而直接在wondow定义的属性可以删除。

var age=1;
window.name="cl"

窗口关系和框架

如果页面包含框架,则每个框架都有自己的window对象,保存在frames集合中。
在frames集合中,可通过数值索引,框架名来访问相应的对象。
每个window对象都有一个name属性(框架名称)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<!---不可用body包裹-->
<frameset rows="160 *" >
<frame src="./text copy.html" name="topF"/>
<frame src="https://developer.mozilla.org/en/HTML/Element/frame" />
</frameset>
</html>

window.frames[0]
window.frames[‘topF”]
top.frames[0]
top对象始终指向最高的框架(浏览器窗口)。
window对象指向的是某个框架的特定实例。
parent对象始终指向当前框架的直接上层框架

除非最高层窗口是通过window.open()打开的,否则window.name不包含任何值
self始终指向window,可互换使用

在使用框架的情况下,浏览器中会有多个Global对象,每个对象中定义的全局变量会自动生成为框架中window对象的属性。由于每个window对象都包含原生类型的构造函数,每个框架都有自己的一套构造函数,这些构造函数一一对应,但并不相等。top.Object != top.frames[0].Object
影响instanceof

窗口位置

Window.screenLeft 是一个只读属性,它返回浏览器左边框到左边屏幕边缘的 CSS 像素数。

注意:screenLeft 只是 Window.screenX 属性的别名,最初只被 IE 浏览器所支持。现在主流的浏览器都已支持该属性。

将窗口移动到一个新的位置
moveTo() //参数:新位置的坐标
moveBy() //水平垂直方向上移动的像素值。

window.open(
"http://www.domainname.ext/path/ImgFile.png",
"DescriptiveWindowName",
"width=420,height=230,resizable,scrollbars=yes,status=1,screenX=500"
);

窗口大小

确定浏览器窗口的大小
innerWidth,innerHeight
outWidth,outHeight

页面视口信息

  • 标准模式document.compatMode == “CSS1Compat”
    document.documentElement.clientWidth
  • 混杂模式
    document.body.clientWidth

调整浏览器窗口的大小
resizeTo()
resizeBy()

导航和打开窗口

window.open()
既可导航到一个特定的URL,也可打开一个新的浏览器窗口
参数:要加载的URL,窗口目标,特定字符串,表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。

如传递了第二个参数,且是已有窗口或框架的名称。就会在具有该名称的窗口或框架中加载URL

//等用于<a href="www." gerget="topFrame" />
window.open("www.",topFrame)

有该窗口或框架,在这加载URL,否则,创建新窗口
_self
_parent
_top
_blank

  1. 弹出窗口
设置 说明
height 新窗口的高度
munubar no 是否显示菜单栏
resizable no 可否通过拖动浏览器的边框改变其大小
  1. 弹出窗口屏蔽程序
//准确检测弹出窗口是否被屏蔽
var blocked=false;
try{ 

var wro=window.open("www.","_blank")
if(wro==null){ 

//
blocked=true;
}
}catch(er){ 

blocked=true;
}
if(blocked){ 

//
}

间歇调用和超时处理(定时器)

setTimeout()
第二个参数告诉js过多长时间把当前任务添加到队列中
clearTimeout()

代码在全局环境中执行的,在非严格模式下this指向window,严格模式下是undefined.

setInterval()

系统对话框

alert()
confirm()
prompt()

location对象

提供与当前窗口中加载的文档有关的信息,提供导航功能。
既是window对象的属性,也是document对象的属性

属性名 例子 说明
hash #contents 返回URL中的hash(#后的零个或多个字符),如URL中不含散列,返回“”
host www.bai.com:80 返回服务器名称和端口号
hostname www.bai.com 返回不带端口号的服务器名称
href http:/www.bai.com 返回页面的完整URL,location.toString()也返回这个值
pathname /will/ 返回URL的目录或文件名
port 8080 端口号
protocol http: 协议
seaarch ?q=js 查询字符串,?

查询字符串参数

location.search可返回?到url末尾的所有内容

function getQueryStringArge(){ 

//取得查询字符串去掉开头的问好
var qs=[location.search.length>0?location.search.substring(1):""],
//保存数据的对象
args={ 
},
//取得每一项
items=qs.length ? qs.split("&") : [],
item=null,
name=null,
value=null,
//在for循环中使用
i=0,
len=items.length;
//捉个将每一项添加到args中
for(i=0;i<len;i++){ 

item=items[i].split("=")
name=decodeURLComponent(item[0])
value=decodeURLComponent(item[1])
if(name.length){ 

args[name]=value
}
}
return args
}

位置操作

location.assign(“http://www.wo.com”)
立即打开新的URL并生成一条记录
location.href
window.location

navigator

oscpu

acreen

history

go()
back()
forward()

13. 客户端检测P262

var client=function(){ 

//呈现引擎
var engine={ 

ie:0,
gecko:0,
webkit:0,
khtml:0,
opera:0,
//完整的版本号 
ver:null
}
//浏览器
var browser={ 

//l主要浏览器
ie:0,
firefox:0,
safari:0,
kong:0,
opera:0,
chrome:0,
//具体的版本号
ver:null
}
//平台,设备,操作系统
var system={ 

win:false,
mac:false,
xll:false,
//移动设备
iphone:false,
ipod:false,
ipad:false,
ios:false,
android:false,
nokiaN:false,
winMobile:false,
//游戏系统
wii:false,
ps:false
}
//检测呈现引擎,浏览器
var ua=navigator.userAgent;
if(window.opera){ 

engine.ver=browser.ver=window.opera.version();
engine.opera=browser.opera=parsePloat(engine.ver)
}else if(/AppleWebkit\/(\S+)/.test(ua)){ 

engune.ver=RegExp["$1"]
engine.webkit=parseFloat(engine.ver)
//确定是chrome还是Safari
if(/Chrome\/(\S+)/.test(ua)){ 

browser.ver=
}
}
}

14. DOM

文档对象模型针对HTML和XML文档的一个API(应用程序接口)。
描绘了一个层次化的节点树,允许开发人员添加,移除,修改页面的部分。

节点层次

节点分为不同的类型,每种类型表示文档中不同的类型、标记。
每个节点拥有各自的特点、数据、方法、与其他节点存在关系。

Node类型

js中的所有节点都继承自Node类型,所有节点都共享相同的属性,方法。
nodeType:节点的类型

  • Node.ELEMENT_NODE 1
  • Node.ATTRIBUTE_NODE 2
  • Node.TEXT_NODE 3
  • Node.CDATA_SECTION_NODE 4
  • Node.ENTITY_REFERENCE_NODE 5
  • Node.ENTITY_NODE 6
  • Node.PROCESSION_INSTRUCTION_NODE 7
  • Node.COMMENT_NODE 8
  • Node.DOCUMENT_NODE 9
  • Node.DOCUMENT_TYPE_NODE 10
  • Node.DOCUMENT_FRAGMENT_NODE 11
  • NodE.NOTATION_NODE 12
if(someNode.nodeType == Node.ELEMENT_NODE){ 

}
//使用所有浏览器
if(someNode.nodeType == 1){ 

}

并非所有节点类型都受浏览器支持。常用的元素、文本节点。

nodeName nodeValue属性

节点的具体信息。
对元素节点,nodeName为元素的标签名,nodeValue始终为null.

节点关系

子元素 父元素
每个节点都有一个childNodes属性,保存着一个NodeList对象。类数组对象

someNode.childNodes[0]
someNode.childNOdes.item(1)

arguments对象,NodeList对象使用Arrary.prototype.slice()可转为数组。

//ie中将NodeList转数组里
function convertoArray(nodes){ 

var array=null;
try{ 

array=Array.prototype.slice.call(nodes,0)
}catch(ex){ 

//ie中将NodeList转数组,手动枚举所有成员
array=new Array()
for(var i=0,len=nodes.length;i<len;i++){ 

array.push(nodes[i])
}
}
return array
}

parentNode父节点
previousSibling前一个同胞节点
nextSibling 后一个同胞节点
firstChild 第一个子节点 someNode.childNodes[0]
lastChild 最后一个子节点 someNode.childNodes[someNode.childNodes.length-1]
hasChldNodes()包含一个或多个子节点返会true
ownerDocument整个文档的文档节点,不必在节点层次中层层回溯到,可直接访问到整个文档节点

操作节点

appendChild() 向childNodes列表的末尾添加一个节点

如传入的节点已是文档的一部分,则将该节点从原来位置移动到新位置。
DOM树看成是由一系列的指针连接起来的,但任何节点不能同时出现在文档的多个位置上。
如果传入父节点的第一个子节点,那么该节点会成为父节点的最后一个字节点。

var returnedNode=someNode.appendChild(someNode.firstChild)
returnedNode==someNode.lastChild

insertBefore() 把节点放在childNodes列表的特定位置。

参数:要插入的节点,作为参考的节点
如参考节点为null,与appendChild相同

replaceChild() 替换节点

参数:要插入的节点,要替换的节点,

removeChild() 移除节点

参数:要移除的节点
被移除的节点仍为文档所有,只不过文档中没有自己的位置

其他

cloneNode()

参数:Boolean
是否执行深复制。true:复制节点及整个字节点树 false:只复制节点本身

normalize()

Document类型

js通过Document类型表示文档。document对象的HTMLDocument的一个实例,表示整个html页面。document对象是window对象的一个属性,作为全局对象访问。
特征:

  • nodeType 9
  • nodeName #document
  • nodeValue null
  • parentNode null
  • ownerDocument null
  • 字节点可能是一个DocumentType(最多一个),Element(最多一个),ProcessingIntruction,Comment

子节点

始终指向html页面的<html>元素
document.documentElement
document.childNodes[0]
document.firstChild

body属性直接指向<body>元素
document.body

一个可能的字节点
document.doctype

文档信息

提供网页的一些信息
title
URL 完整url
domain 页面的域名

是可设置的,但只能设置为url中包含的域,子域名

referrer 链接到当前页面url
存在与http的头部

查找元素

getElementById()

参数:取得元素的id

getElementsByTagNma()

参数:标签名
返回HTMLCollection对象

getElelmentsByName()

文档写入

将输入流写入网页中
write() 原样写入
writeIn() 会在字符串的末尾添加一个换行符\n

Element类型

提供对元素标签名,子节点及特性的访问

  • nodeType 1
  • nodeName 元素的标签名tagName
  • nodeValue null
  • parentNode Document,Element
  • 子节点可能是Element,Text,Comment,ProceddingInstruction,CDATASection,EntityReference

标签名全部大写
element.tagName.toLowerCase() == “div”

HTML元素

所有HTML元素都有HEMLElement类型及其自类型表示。
HEMLElement继承Element并添加一些属性。

  • id 元素的唯一标识
  • title
  • lang
  • className
  • dir 语言方向,ltr(left-to-right从左向右) rtl

div.className 可取得值,也可赋给新值

取得特性

getArrtibute()
setAtrribute() 设置特性
removeAttribute() 删除特性
传入特性名与实际特性名相同
也可取得自定义特性的值,自定义特性因加上data-前缀

属性的值,和通过getAttribute()返回值不相同的情况:

特性 属性的值 getAttribute()
style 对象 css文本
onclick这样的事件 js代码 代码的字符串

通常不使用getAttribute(),

attributes属性

Element类型是使用attributes属性的唯一一个节点类型。attributes属性包含一个NamedNodeMap.
元素的每个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。

  • getNamedItem(name) nodeName属性等于name的节点
  • removeNamedItem(name)
  • setNamedItem(node) 像列表中添加节点,以节点的nodeName属性为索引
  • item(pos) 返回位于数字pos位置的节点

attributes属性中包含一系列节点,每个节点的nodeName就是特性的名称,而节点的nodeValue是特性的值。

//取得元素的id特性
var id=element.attributes.getNamedItem("id").nodeValue;
var id=element.attributes["id"].nodeValue

创建元素

document.createElement(“div”)
尚未添加到文档树

子节点

Text类型

文本节点

  • nodeType 3
  • nodeName #text
  • nodeValue 所包含的文本 data
  • parentNode Element
  • 没有子节点
  • appendData(text) 将text添加到节点的末尾
  • deleteData(offset,count) 从offset指定位置开始删除count个字符
  • insertData(offset,text) 从offset指定位置插入count个字符
  • replaceData(offset,count,text) 用text替换从offset指定位置开始到offset+count为止处的文本
  • splitText(offset) 从offset指定的位置将当前文本分为两个文本节点
  • subStringData(offset,count) 提取从offset指定位置开始到offset+count为止处的文本
  • length 节点字符的数目

创建文本节点

document.createTextNode()

规范化文本节点

normalize() 将所有文本节点合并成一个节点

分割文本节点

splitText()

Comment类型

注释

  • nodeType 8
  • nodeName #comment
  • nodeValue 注释的内容
  • parentNode Document Element
  • 没有子节点
  • Comment和Text继承自相同的基类,拥有除splitText()之外的所有字串方法。

document.createComment(“comment”)

CDATASection类型

DocumenType

DocumenFragment类型

在文档中没有相应的标记
文档片段是一种轻量级文档,可包含和控制节点,不会向完整文档那样占用额外的资源。

  • nodeType 11
  • nodeName #document-fragment
  • nodeValue null
  • parentNode null

不能直接把文档片段添加到文档中,可作为仓库使用
document.createDocumentFragment()
避免浏览器反复渲染

Attr

元素的特性

DOM操作技术

动态脚本

15. DOM扩展

选择符

querySelector()
querySelectorAll()
matchesSelector()
getElementsByClassName()

classList属性

add(value) 添加
contains(value) 是否存在
removeI(value) 删除
toggle(value) 存在删除,没有添加

//切换user类
div.classList.toggle("user")

焦点管理

document.activeElement属性会始终引用DOM中获得焦点的元素
focus()
hasFocus()

16. DOM2 DOM3

元素的大小

偏移量

  • offsetHeight:元素在垂直方向上占用的空间大小,包括元素的高度,(可见的)水平滚动条的高度,上下边框的高度
  • offsetWidth:
  • offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。
  • offsetTop

在这里插入图片描述

客户区大小

clientWidth:元素内容区宽度加左右内边距宽度
clientHeight:
在这里插入图片描述

滚动大小

  • scrollHeight:没有滚动条的情况下,元素内容的总高度,元素实际大小
  • scrollWidth:
  • scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可改变元素的滚动位置
  • scrollTop

在这里插入图片描述

确定元素的大小

getBoundingClioentRect()
返回一个矩形对象,包含4个属性:left,top,right,bottom.
给出元素在页面中相对视口的位置

17. 事件

事件流

页面中接收事件的顺序
ie:事件冒泡流
事件捕获流

事件冒泡

事件开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐渐向上传播到较为不具体的节点(文档)。
在这里插入图片描述

事件捕获

不太具体的节点应该更早接收到事件,而最具体的节点应最后接收到事件。
事件到达预定目标之前捕获它。
在这里插入图片描述

DOM事件流

在这里插入图片描述

事件处理程序

相应事件的函数
事件处理程序以on开头

HTML事件处理程序

<div onclick="alert(11)">
<div onclick="show()">

event事件对象,不必定义它,
this事件的目标元素

DOM0级事件处理程序

通常全部小写
DOM0级事件处理程序被认为是元素的方法。事件处理程序在元素的作用域中运行,即:程序中的this引用当前元素。

btn.onclick=function(){ 

//通过this可访问元素的任何属性,方法
console.log(this.id)
}
//删除事件处理程序
btn.onclick=null;

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

DOM2级事件处理程序

addEventListener()
removeEventListener()

参数:要处理的事件名,作为事件处理程序的函数,Boolean(true:捕获阶段调用事件处理程序,false:冒泡阶段调用)

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段。
最好只在需要在事件到达目标之前截获它的时候将事件添加到捕获阶段。

ie事件处理程序

attachEvent()
detachEvent()

参数:
事件被添加到冒泡阶段

第一个参数:onclick,而非addEventListener的click

ie中使用dom0的方法,事件处理程序被添加到元素的作用域内运行;使用attachEvent(),事件在全局作用域中运行,this==window

跨浏览器的事件处理程序

事件对象

DOM中的事件处理对象

var btn=documnet.getElementByID("myBtn")
btn.onclick=(event)=>{ 

//
}
btn.addEventListente("click",(erent)=>{ 

//
})

event对象包含与创建它的特定事件乡关的属性和方法。

属性/方法 类型 读/写 说明
bubbles Boolean 只读 事件是否冒泡
cancelabel Beeleaan 只读 是否可取消事件的默认行为
currentTarget Element 只读 当前正在处理事件的元素
defaultPrevented B 只读 为true表示已调用preventDefault()
detail Integer 只读 细节信息
eventPhase Integer 只读 调用事件处理程序的阶段:1捕获阶段,2处于目标阶段,3冒泡阶段
preventDefault() Function 只读 取消事件默认行为,如cancelable为true,则可调用
stopImmediatePropagation() F 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation() F 取消事件的进一步捕获或冒泡,如bubbles为true,则可用
target E 事件目标
trusted B true事件有浏览器生成的
type String 事件的类型
view

在事件处理程序内部,this始终等于currentTarget的值,target则包含事件的实际目标。

如直接将事件指定给目标元素,this,currentTarget,target相同

document.body.onclick=(event)=>{ 

//event.currentTarget===document.body
//this===document.body
//event.target===document.getElementById("btn")
}

按钮是click事件真正的目标,事件冒泡的document.body,在哪里事件菜得到处理
阻止事件的默认行为,preventDefault()

链接的默认行为是点击时导航到href特性的URL。

cancelable为true,时才可使用。

stopPropagation()

立即停止事件在DOM层的传播

var btn=document.getElementById("id")
btn.onclick=()=>{ 

}
documnet.body.onclick=()=>{ 

}

事件类型

UI事件

document.implementation.hasFeature("HTMLEvents","2.0")

load事件

页面完全加载后(包括所有图像,js文件,css文件等外部资源)触发

<body onload="alert()">
<img onload="alert()">
</body>

unload

文档完全卸载后触发

resize

浏览器窗口调整时触发

window.onresize=()=>{ 
alert(1)}

scroll

滚动期间重复触发

焦点事件

在页面获得或失去焦点时触发。

利用这些事件,document.hasFocus(),documnet.activeElement()配合可知晓用户在页面上的行踪。

blur

元素失焦,不会冒泡

DOMFocusIn

focus

元素获得焦点,不会冒泡

focusin

元素获得焦点,会冒泡

focusout

鼠标与滚轮事件

click

单击或按下回车键时触发

dbclick

双击

mousedown

按下任意鼠标按钮时触发

mouseenter

光标首次移入元素范围之内时触发,不冒泡,且光标移动到后代元素上不触发

mouseleave

mousemove

鼠标指针在元素内移动时重复触发

mouseout

鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。

移入的另一个元素可能位于前一个元素的外部,也可能是子元素。

mouseover

鼠标指针位于一个元素外部,用户首次移入另一个元素边界时触发。

mouseup

释放鼠标按钮时触发

客户区坐标位置

clientX,clientY
事件发生时鼠标在视口中的水平和垂直位置
不包含页面滚动的距离
在这里插入图片描述

页面坐标位置

pageX,pageY
坐标是从页面本身而非视口的左边和顶边计算的

页面没有滚动的情况下与pageX相等

var pageX=event.pageX,
pageY=event.pageY;
if(pageX===undefined){ 

pageX=event.clientX+(document.body.scrollLeft || document.documentElement.scrollLeft);
}

屏幕坐标位置

screenX,screenY

在这里插入图片描述

修改键

按下鼠标时键盘上的某些键的状态可以影响到索要采取的操作,
shift,ctrl,alt,meta
event.shiftKey
ctrlKsy
altKey
metaKey

相关元素

mouseover,mouseout,会涉及更多的元素。
都会涉及把鼠标从一个元素的边界之内移动到另一个元素的边界之内。
mouseover:事件的主要目标是获得光标的元素,相关元素的失去光标的元素。
mouseout:

relatedTarget:包含相关元素的信息。
ie:
mouseover:fromElement
mouseout:toElement

鼠标按钮

0:主鼠标按钮
1:中间鼠标按钮
2:次鼠标按钮

滚轮事件

mousewheel
当用户向前滚动滚轮时,wheelDelta是120的倍数

触摸设备

iOS,Android

  • 不支持dbclick事件。双击浏览器会放大画面,
  • 轻击可单击元素会触发mousemove事件。如此操作导致页面变化,将不在有其他事件发生;如屏幕没因此变化,会依次触发mousedown,mouseup,click事件。
  • mousemove事件也会触发mouseover,mouseout事件
  • 两个手指放在屏幕且页面随手指滚动时触发mousewheel,scroll事件

键盘和文本事件

  • keydown:按下任意键触发,按住不放,会重复触发
  • keypress:按下字符键会触发,Ese键也会触发
  • keyup:释放键时触发

文本事件

  • textInput:将文本显示给用户前拦截文本。文本插入文本框前触发。data

键码

keyCode
非字符键的键码

键码
退格backspaace 8

DOM3级变化

key
char
keyIdentifier

HTML5事件

contextmenu事件

右键调出上下文菜单

document.oncontextmenu=(e)=>{ 

console.log(1)
e.preventDefault()
var menu=document.getElementById("menu")
menu.style.left=e.clentX+"px";
menu.style.top=e.clentY+"px";
menu.style.visibility="visible";
}
document.onclick=(e)=>{ 

menu.style.visibility="hideen";
}

feforeunload

页面卸载前阻止
event.returnValue(“you will go”)

DOMContentLoaded

在形成完整的DOM树后就触发

pageshow pagehide

往返缓存(bfcache),可使“后退”,前进,时加快页面的转换速度。
这个缓存中不仅保存着页面的数据,还保存这dom,js的状态。
页面处于bdcache时,再次打开页面不会触发load事件。
pageshow:
页面显示时触发,重新加载的页面,pageshow在load事件后触发,对dbcache中的页面,pageshow在页面状态完全恢复后触发。
虽然这个事件的目标是document,但必须将事件处理程序添加到window。

 window.addEventListener('pageshow', function(event) { 

//event.persisted属性为true时,表示当前文档是从往返缓存中获取
if(event.persisted) { 
location.reload();  
console.log( 'popstate');}
});

pagehide:
unload事件之前触发
如页面在卸载后会被保存在bfcache中,则persisted的值会被设置为true。

haschange

url参数列表(及url中#后面的所有字符)发生变化时触发。
ajax应用中,利用url参数保存状态或导航信息。

触摸和手势事件

触摸事件

  • touchstart:手指触摸屏幕时触发
  • touchmove:手指在屏幕上滑动时触发
  • touchend:手指从屏幕上移开时触发

内存和性能

添加到页面的事件处理程序数量直接关系页面运行性能。
函数都是对象,会占用内存。
必须事先指定多有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

事件委托

利用事件冒泡,指定一个事件处理程序,就可管理某一类型的多有事件。

如果可行的话,可考虑为documemt对象添加一个事件处理程序,优点:

  • document对象可以很快被访问,可在页面的生命周期的任何时间点上添加(无需等待DOMContentLoaded或load事件)
  • 在页面中设置事件处理程序需要的时间更少,只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少。
  • 内存减少。

适合采用事件委托的事件包括:click,mousedown,mouseup,keydown,keyup,keypress

移除事件处理程序

当将每个事件处理程序指定给元素时,运行中的浏览器与js间便会建立一个连接。这种链接越多,页面执行就越慢。

btn.onclick=()=>{ 

bun.onclick=null;
document.getElemenmtById("myBtn").innerHTML="Processing..."
}

为了避免双击,点击时将按钮移除替换成一条消息。
可按钮被移除时,还带着一个事件处理程序。

模拟事件

使用js在任意时刻来触发特定的事件

DOM中的事件模拟

createEvent()
参数:要创建的事件类型

dispatchEvent() 触发事件
参数:event对象

模拟鼠标事件

  • type:要触发的事件类型
  • bubbles:受否冒泡
  • cancelable:是否可取消
  • view:视图,doucument.defaultView
  • detail:0
  • screenX:相对于屏幕的x坐标
  • screenY:
  • clientX:想对于视口的x
  • clientY
  • ctrlKey:是否按下ctrl,false
  • altKey:
  • shiftKey:
  • metaKey:
  • button:按下哪个鼠标键。0
  • relatedTarget
var event=document.createEvent("mouseEvents")
event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null)
btn.dispatchEvent(event)

模拟键盘事件

18 动画与 Canvas 图形

18.1 使用requestAnimationFrame

18.1.1 早期定时动画

这种定时动画的问题在于无法准确知晓循环之间的延时。定时间隔必须足够短,这样才能让不同的
动画类型都能平滑顺畅,但又要足够长,以便产生浏览器可以渲染出来的变化。一般计算机显示器的屏
幕刷新率都是 60Hz,基本上意味着每秒需要重绘 60 次。大多数浏览器会限制重绘频率,使其不超出屏
幕的刷新率,这是因为超过刷新率,用户也感知不到。
因此,实现平滑动画最佳的重绘间隔为 1000 毫秒/60,大约 17 毫秒。以这个速度重绘可以实现最平
滑的动画,因为这已经是浏览器的极限了。如果同时运行多个动画,可能需要加以限流,以免 17 毫秒
的重绘间隔过快,导致动画过早运行完。
虽然使用 setInterval()的定时动画比使用多个 setTimeout()实现循环效率更高,但也不是没
有问题。无论 setInterval()还是 setTimeout()都是不能保证时间精度的。作为第二个参数的延时
只能保证何时会把代码添加到浏览器的任务队列,不能保证添加到队列就会立即运行。如果队列前面还
有其他任务,那么就要等这些任务执行完再执行。简单来讲,这里毫秒延时并不是说何时这些代码会执
行,而只是说到时候会把回调加到任务队列。如果添加到队列后,主线程还被其他任务占用,比如正在
处理用户操作,那么回调就不会马上执行。

function updateProgress() { 
 
var div = document.getElementById("status"); 
div.style.width = (parseInt(div.style.width, 10) + 5) + "%"; 
if (div.style.left != "100%") { 
 
requestAnimationFrame(updateProgress); 
} 
} 
requestAnimationFrame(updateProgress);

18.1.4 cancelAnimationFrame

18.2 基本的画布功能

必须先设置width,height,指定和绘制的区域大小
要在canvas上绘图,需取得绘图上下文。要取得绘图上下文,需调用getContext()并传入上下文名称

var drawing=document.getElementById("drawing")
if(drawing.getContext){ 

var context=drawing.getContext("2d")
//
}

使用toDataURL(),可导出canvas元素上绘制的图形。
参数:MIME类型
drawing.toDataURL(“image/png”)

2D上下文

坐标始于cancas元素的左上角,原点坐标(0,0)。所有坐标值基于这个原点计算,x值越大越靠右,y值越大越考下

填充和描边

填充
利用指定样式(颜色,渐变,图像)填充图形
fillStyle

描边
在图行的边缘画线
strokeStyle

样式设置后,所有涉及操作都将使用这两个样式,直到重新设置。

绘制矩形

参数:矩形的x坐标,矩形的y坐标,矩形的宽度,矩形的高度

fillRect()
绘制矩形填充指定颜色,fillStyle

strokeRect()
绘制矩形以指定颜色描边,strokeStyle

clearRect()
清除画布上的矩形区域

绘制路径

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,k)为止

moveTo(x,y)
将绘图游标移动到(x,y),不画线

quadraticCurveTo(cx,cy,x,y)
从上一点绘制一条二次曲线,到(x,y)为止,以(cx,cy)作为控制点

rect(x,y,width,height)
从点(x,y)开始绘制一个矩形,

closePath()
连接路径起点的线条

fill()
用fillStyle填充

stroke()
用strokeStyle对路径描边

clip()
在路径上创建一个剪切区域

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()
}

绘制文本

参数:要绘制的文本字符串,x坐标,y坐标,[最大像素宽度]
fileText()

strokeText()

font:文本样式,大小,字体
textAlign:文本对齐方式,start,end,left,right,center
textBaseline:文本基线,top,hanging,middle,alphabetic,ideographic,bottom

context.font="bold 14px Arial"
context.textAlign="center"
context.textBaseLine="middle"
context.fillText("12",100,20)

变换

rotate(angle)
围绕原点旋转图像angle弧度

scale(scaleX,scaleY)
缩放图像

translate(x,y)
将坐标原点移动到(x,y)

绘制图像

drawImage()
参数:要绘制的图像,源图像的x坐标,源图像的y坐标,源图像的width,源图像的height,目标图像的x坐标,目标图像的width,目标图像的height

toDataURL()
图像不能来自其他域,否则认为上下文不干净。

使用图像数据

getImageData()取得原始图像数据
参数:要取得其数据的页面区域的x,y坐标,该区域的像素宽度,高度

返回值:ImageData实例
每个ImageData对象都有三个属性:width,height,data
data属性是一个数组,保存这图像中每一个像素的数据。一个像素用4个元素保存,红,绿,蓝,透明度值。第一个像数的数据保存在数组的0到3个元素中。

能够直接访问到原始图像数据,就能以各种方式操作这些数据。

//修改图像数据,创建一个灰阶过滤器
var drawing=document.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style> #drawing { 
 width: 900px; height: 900px; } </style>
</head>
<body>
<canvas id="drawing"></canvas>
<img src="https://www.html5rocks.com/en/tutorials/canvas/imagefilters/demo_small.png" alt="">
<script> window.onload = () => { 
 var drawing = document.getElementById("drawing") // if (drawing.getContext) { 
 var context = drawing.getContext("2d"), image = document.images[0], i, len, average, red, green, blue, alpha; image.crossOrigin = 'anonymous'; //绘制图像原点 context.drawImage(image, 0, 0) //取得图像数据 imageData = context.getImageData(0, 0, image.width, image.height) data = imageData.data for (i = 0, len = data.length; i < len; i += 4) { 
 red = data[i]; green = data[i + 1] blue = data[i + 2] alpha = data[i + 3] //求rgb平均值 average = Math.floor((red + green + blue) / 3) //设置颜色值,透明度不变 data[i] = average; data[i + 1] = average data[i + 2] = average } //回写图像数据并显示结果 imageData.data = data context.putImageData(imageData, 0, 0) } } </script>
</body>
</html>

只有图片非来自其他域,才可取得图像数据

canvas跨域问题解决方案

https://github.com/zhbhun/frontend-learning/blob/master/issues/canvs-image-cross-domain/ajax.html
https://segmentfault.com/a/1190000016423028

合成

WebGL

19. 表单脚本

19.1 表单基础知识

<form>
HTMLFormElement类型,继承自HTMLElement类型,拥有html元素的默认属性外,拥有自己的属性方法。

  • acceptCharset:服务器能处理的字符集;accept-charset
  • action:接受请求的url;action
  • elements:表单中所有控件的集合
  • enctype:请求编码类型;enctype
  • length:表单中控件的数量
  • method:要发送的http请求类型:get,post;methos
  • name:表单的名字
  • reset():将表单域重置为默认值
  • submit():提交表单
  • target:发送请求和接受响应的窗口的名称

取得<form>元素的引用

  1. document.getElementById(“form1”)
  2. document.forms可取得页面所有表单,通过数字索引或名字name来取得特定的表单
    document.forms[0]
    document.forms[“form2”]

19.1.1 提交表单

提交表单的方式:

<!-- 通用提交表单-->
<input type="submit" value="Submit">
<!--自定义提交表单-->
<button type="submit">Sbumit</button>
<!--图像按钮-->
<input type="image" src=".gif">

只要表单中存在上面任何一种按钮,那么在相应表单控件拥有焦点的情况下,按回车键就可提交该表单。textarea例外,回车换行。没有提交按钮,回车不会换行。

这种方式提交表单时,浏览器会在请求发给服务器之前触发submit事件。这样可验证表单数据,并决定是否允许表单提交。
阻止这个事件的默认行为就可以取消表单提交。
一般来说,表单数据无效,不能发给服务器时,可使用。

let form =document.getElementById("myForm")
form.addEventListener("submit",(e)=>{ 

//阻止表单提交
e.preventDefault();
}
//使用编程方式调用sbumit()方法提交
form.submit()

调用submit()的形式提交表单时,不会触发submit()事件,

防重复提交:在第一次提交表单后就禁用提交按钮。利用onsbumit事件取消后续的表单提交操作。

19.1.2 重置表单

恢复到页面刚加载完毕时的初始值。

<!--通用重置按钮-->
<input type="reset" value="Reset">
<!--自定义重置按钮-->
<button type="reset">reset</button>

点击重置按钮重置表单时,会触发reset事件。

调用reset()方法会像单击重置按钮一样触发reset事件

19.1.3 表单字段

表单元素可以像页面其他元素一样使用原生DOM访问。
elements属性:表单中所有元素的集合。是一个有序列表,包含这表单中的所有字段,可按位置和name特性来访问。

共有的表单字段属性

除,所有的表单字段都拥有相同的属性。

  • disabled:禁用
  • form:所属表单的指针
  • name:
  • readOnly:当前字段是否只读
  • tabIndex:切换序号
  • type:类型,checkbox,radio
  • value:被提交给服务器的值
<select>
<select multiple>

方法

focus()
将浏览器的焦点设置到表单字段了,激活表单字段,使其可以响应键盘事件。
autofocus

blur()

事件

blur:失去焦点是触发

change:input,textarea,在失去焦点且value值改变时触发;select,选项改变时触发

focus:获得焦点时触发

文本框脚本

text
value:设置初始值
maxlength:最大接受的字符数
size:能够显示的字符数

textarea
row:文本框的字符行数
cols:文本框的字符列数

选择文本

select()
文本获取焦点时,选择文本框中所有的文本

select事件

选择文本框的文本时会触发

取得选择的文本

selectionStart
selectionEnd

selection.

选择部分文本

setSelectionRange()
createTextRange()
自动完成建议的文本框

过滤输入

特定数据,特定格式

屏蔽字符

要求输入的文本中不能包含某些特殊字符
响应文本框中插入字符操作的是keypress事件。阻止事件的默认行为来屏蔽此类字符。

//只允许输入数值
var charCode=e.getCharCode()
//非字符触发的keypress事件字符编码<0
//检测用户没有按下Ctrl
if(!/\d/.test(String.fromCharCode(charCode) && charCode>9 && !e.ctrlKey){ 

e.preventDefault()
}

操作剪贴板

copy:发生复制操作时触发
cut:剪切
paste:粘贴

clipboardData

自动切换焦点

function tabForward(e){ 

var tearget=e.targe
if(target.value.length == target.maxLength){ 

var form=target.form
for(var i=0,len=form.elements.length;i<len;i++){ 

if(form.elements[i] == target){ 

if(form.element[i+1]){ 

form.elements[i+1].focus()
}
return
}
}
}
}

HTML5约束验证API

js被禁,

必填

required

其他类型

email
url

数值范围

input.setpUp(1)
input.setpDown(1)

输入模式

pattern

禁用验证

novalidate

选择框脚本

<select>

  • add(newOption,relOption):向控件插入新<option>元素,在相关项<relOption>之前
  • multiple:是否允许多选
  • options
  • remove(index):移除给定位置的选项
  • selectedIndex:基于0的选中项的索引,没选中项,-1
  • size:选择框中可见的行数

<option>

  • index:当前选项在options集合中的索引
  • label:
  • selected:受否被选中
  • text:
  • value

选择选项

对于只允许选一项的选择框 ,selectdIndex

选择多项的选择框:selected

添加选项

var newOption=document.createdElement("option")
newOption.appendChild(document.createTextNode("text"))
newOption.setAttribute("value","text")
var newOption=new Option("text","text")
selectbox.appChild(newOption)
selectbox.add(newOption,undefined)

移除选项

//移除第一项
selectbox.removeChild(selectbox,option[0]);
selectbox.remove(0)
selectbox.options[0]=null

移动和重排选项

appendChild()
insertBefore()

表单序列化

表单提交时,浏览器如何将数据发送给服务器

  • 对表单字段的名称和值进行URL编码,使用&分割
  • 不发送禁用的表单字段
  • 只发送勾选的复选框和单选按钮
  • 不发送type为reset,button的按钮
  • 多选框中每个选中的值单独一个条目
  • 在单击提交按钮提交的情况下,会发送提交按钮,
  • select元素的值就是option元素的value值

hasAttribute()
specified

富文本编辑

包含html页面的iframe,通过设置designMode属性,这个空白的html页面就可被编辑,而编辑对象是该页面body元素的HTML代码。

使用contenteditable属性

另一种富文本编辑的方式

操作富文本

document.execCommand()
参数:要执行的命令名称,表示浏览器是否需提供用户界面,执行命令的必须值

命令 值(第三个参数) 说明
backcolor 颜色字符串 文档的背景颜色
bold null 将选择的文本转换为粗体
copy null 将选择的文本复制到剪贴板
createlink url字符串 将选择的文本转换为一个链接
cut null
delete null
fontname 字体名字
fontsize 1~7 将选择的文本修改为指定的字体大小
forecolor 颜色字符串 将选择的文本修改为指定的颜色
insertimage 图像url 插入一个图像
selectall null 选择所有文本
underline null 为选择的文本添加下划线
document.execCommand("bold",false,null)
document.execCommand("createlink",false,"http://www.")
document.execCommand("formatblock",false,"<h1>")

20. HTML5脚本编程 JavaScript API

详细介绍

跨文档消息传递

postMessage()

原生拖放

拖放事件

媒体元素

属性

属性 数据类型 说明
autoplay B 取得或设置autoplay
controls B 取得或设置controls属性,用于显示或隐藏浏览器内置的控件
currentLoop Int 媒体文件已循环的次数
currentSrc S 当前播放媒体文件的URL
currentTime F 已经播放的秒数
defaultPlaybackRate F 取得或设置默认默认播放速度
duration F 媒体总播放时间
ended B 是否播放完成
loop B 取得或设置媒体文件播放完成后是否从头开始播放
muted B 取得或设置是否静音

历史状态管理

haschange事件
知道url参数什么时候发生变化

history.pushState()
状态管理API,在不加载页面的情况下改变浏览器的url,
参数:状态对象,新状态的标题,相对url
第二个参数可传入一个空字符串
会创建新的历史状态,可“后退”,会触发popstate事件。

popstate事件
有一个state属性,包含当初第一个参数传给pushState()的状态对象
得到状态对象后,需自己把页面重置为状态对象中数据表示的状态。

replaceState()
跟新当前状态,不会在历史状态栈中创建新状态,只会重写当前状态。

history.replaceState({ 
name:"cc"},"")

21. 错误处理和调试

详细介绍

错误处理

服务端团队在错误处理机制上投入精力。按照类型,频率,对错误进行分类

22. 处理 XML

23. Json

语法

简单值

“hello”

对象

{

“name”:“cc”,
“age”:29
}

数组

[25,“hi”,true]

解析与序列化

JSON对象

eval()

stringify()
把js对象序列化为JSON字符串
第二个参数:可是数组,函数
第三个参数:是否在json字符串中保留缩进

toJSON()

parse()
把JSON字符串解析为js对象

24. 网络请求与远程资源

Ajax与Comet
XHR比较难用,迅速被fetch API替代,支持期约promise,服务线程service worker.

XMLHttpRequest对象

var xhr=new XMLHttpRequest()

XHR的用法

open()
调用open()不会实际发送请求,只是为发送请求做好准备。

//参数:要发送的请求类型(get,post),请求url,是否异步发送请求
xhr.open("get","example.php", false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { 

alert(xhr.responseText);
} else { 

alert("Request was unsuccessful: " + xhr.status);
}

send()
要发送定义好的请求
参数:作为氢气主体发送的数据,如果不需要发送请求体,则必须传null,

同步请求,收到响应后,响应的数据会自动填充XHR对象的属性

  • responseText:作为响应主体被返回的文本
  • responseXML:如响应内容类型是text/xml,application/xml,那就是包含响应数据的XML DOM 文档。
  • status:响应的HTTP状态
  • statusText:http状态的说明

异步请求,检测XHR对象的readyState属性

  • 0:未初始化,尚未调用open()
  • 1:启动,已调用open(),未调用send()
  • 2:发送,已调用send(),未接收到响应
  • 3:接收,已接收到部分数据
  • 4:完成,已接收到全部响应数据

readyState属性的值变化时,会触发readystatechange事件。


let xhr = new XMLHttpRequest();
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头部信息

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

setRequsetHeader()
可设置自定义的头部信息

getResponseHeader()
取得响应头部信息

getAllResponseHeader()
返回包含所有响应头部的字符串

GET请求

用于向服务器查询某些信息
发送GET 请求最常见的一个错误是查询字符串格式不对。查询字符串中的每个名和值都必须使用
encodeURIComponent()编码,所有名/值对必须以和号(&)分隔,如下面的例子所示:
xhr.open(“get”, “example.php?name1=value1&name2=value2”, true);

POST请求

模仿web表单提交
Content-Type:application/x-www-formurlencoded

xhr.open("post", "postexample.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
let form = document.getElementById("user-info");
xhr.send(serialize(form));

PHP 文件
postexample.php 随后可以通过$_POST 取得POST 的数据。

<?php
header("Content-Type: text/plain");
echo <<<EOF
Name: { 
$_POST['user-name']}
Email: { 
$_POST['user-email']}
EOF;
?>

假如没有发送Content-Type 头部,PHP 的全局$_POST 变量中就不会包含数据,而需要通过
$HTTP_RAW_POST_DATA 来获取。

XMLHttpRequest 2级

FormData

表单数据序列化
序列化表单,创建与表单格式相同的数据

var data=new FormData()
data.append("name","cc")

append()方法接收两个参数:键和值,相当于表单字段名称和该字段的值。可以像这样添加任意
多个键/值对数据。此外,通过直接给FormData 构造函数传入一个表单元素,也可以将表单中的数据作为键/值对填充进去:

let data = new FormData(document.forms[0]);
有了FormData 实例,可以像下面这样直接传给XHR 对象的send()方法:
let xhr = new XMLHttpRequest();
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);
let form = document.getElementById("user-info");
xhr.send(new FormData(form));

使用FormData 的另一个方便之处是不再需要给XHR 对象显式设置任何请求头部了。XHR 对象能
够识别作为FormData 实例传入的数据类型并自动配置相应的头部。

超时设定

timeout

xhr.timeout = 1000; // 设置1 秒超时
xhr.ontimeout = function() { 

alert("Request did not return in a second.");
};

overrideMimeType()

用于重写XHR 响应的MIME 类型。

let xhr = new XMLHttpRequest();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null);

进度事件

loadstart
在接收到响应数据的第一个字节时触发

progress
在接收响应期间不断触发
e.target XHR对象
e.target.lengthComputable 进度信息是否可用
e.target.position 已接收的字节数
e.target.totalSize 预期字节数

xhr.onprogress = function(event) { 

let divStatus = document.getElementById("status");
if (event.lengthComputable) { 

divStatus.innerHTML = "Received " + event.position + " of " +
event.totalSize +
" bytes";
}
};

error
请求错误时触发

abort
因调用abort()方法终止连接时触发

load
接收到完整响应数据时触发 在成功接收完响应时触发

load 事件在响应接收完成后立即触发,这样就不用检查readyState 属性
了。onload 事件处理程序会收到一个event 对象,其target 属性设置为XHR 实例,在这个实例上
可以访问所有XHR 对象属性和方法。

let xhr = new XMLHttpRequest();
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);

loadend
在通信完成,error,abort,load

跨域资源共享

只能访问同源URL,也就是域名相同、端口相同、协议相同

CORS: 使用自定义的HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应应该成功还是失败。

Origin:发送请求时附加,头部包含发送请求的页面的源(协议、域名和端口),以便服务器确定是否为其提供响应。
Origin:http://www.com

服务器返回
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Origin:”*” //公共资源

默认情况下,跨源请求不提供凭据(cookie、HTTP 认证和客户端SSL 证书)。可以通过将
withCredentials 属性设置为true 来表明请求会发送凭据。如果服务器允许带凭据的请求,那么可
以在响应中包含如下HTTP 头部:
Access-Control-Allow-Credentials: true

替代性跨域技术

不需要修改服务器

图片探测

图片探测的缺点是只能发
送GET 请求和无法获取服务器响应的内容。这也是只能利用图片探测实现浏览器与服务器单向通信的
原因。

let img = new Image();
img.onload = img.onerror = function() { 

alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";

24.4.2 JSONP

JSONP 是从不同的域拉取可执行代码

跟JSON 一样,只是会被包在一个函数调用里,比如:
callback({ “name”: “Nicholas” });
JSONP 格式包含两个部分:回调和数据。回调是在页面接收到响应之后应该调用的函数,通常回调
函数的名称是通过请求来动态指定的。而数据就是作为参数传给回调函数的JSON 数据。下面是一个典
型的JSONP 请求:
http://freegeoip.net/json/?callback=handleResponse

function handleResponse(response) { 

console.log(` You're at IP address ${ 
response.ip}, which is in ${ 
response.city}, ${ 
response.region_name}`);
}
let script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

Fectch API

必须是异步
API 也能够应用在服务线程
(service worker)中,提供拦截、重定向和修改通过fetch()生成的请求接口。

24.5.1 基本用法

  1. 分派请求
    fetch()只有一个必需的参数input。多数情况下,这个参数是要获取资源的URL。这个方法返回
    一个期约:
let r = fetch('/bar');
console.log(r); // Promise \<pending>
fetch('bar.txt')
.then((response) => { 

console.log(response);
});
// Response { type: "basic", url: ... }
  1. 读取响应
    读取响应内容的最简单方式是取得纯文本格式的内容,这要用到text()方法。这个方法返回一个
    期约,会解决为取得资源的完整内容:
    fetch(‘bar.txt’)
    .then((response) => {

    response.text().then((data) => {

    console.log(data);
    });
    });
    // bar.txt 的内容
    内容的结构通常是打平的:
    fetch(‘bar.txt’)
    .then((response) => response.text())
    .then((data) => console.log(data));
    // bar.txt 的内容
  2. 处理状态码和请求失败
    Fetch API 支持通过Response 的status(状态码)和statusText(状态文本)属性检查响应状
    态。成功获取响应的请求通常会产生值为200 的状态码,如下所示:
    fetch(’/bar’)
    .then((response) => {

    console.log(response.status); // 200
    console.log(response.statusText); // OK
    });
    请求不存在的资源通常会产生值为404 的状态码:

因为服务器没有响应而导致浏览器超时,这样真正的fetch()失败会导致期约被拒绝:
fetch(’/hangs-forever’)
.then((response) => {

console.log(response);
}, (err) => {

console.log(err);
});
//(浏览器超时后)
// TypeError: “NetworkError when attempting to fetch resource.”
4. 自定义选项
可选参数init对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

24.5.2 常见Fetch 请求模式

  1. 发送JSON 数据
    可以像下面这样发送简单JSON 字符串:
    let payload = JSON.stringify({

    foo: ‘bar’
    });
    let jsonHeaders = new Headers({

    ‘Content-Type’: ‘application/json’
    });
    fetch(’/send-me-json’, {

    method: ‘POST’, // 发送请求体时必须使用一种HTTP 方法
    body: payload,
    headers: jsonHeaders
    });
  2. 在请求体中发送参数
    因为请求体支持任意字符串值,所以可以通过它发送请求参数:
    let payload = ‘foo=bar&baz=qux’;
    let paramHeaders = new Headers({

    ‘Content-Type’: ‘application/x-www-form-urlencoded; charset=UTF-8’
    });
    fetch(’/send-me-params’, {

    method: ‘POST’, // 发送请求体时必须使用一种HTTP 方法
    body: payload,
    headers: paramHeaders
    });
  3. 发送文件
    因为请求体支持FormData 实现,所以fetch()也可以序列化并发送文件字段中的文件:
    let imageFormData = new FormData();
    let imageInput = document.querySelector(“input[type=‘file’]”);
    imageFormData.append(‘image’, imageInput.files[0]);
    fetch(’/img-upload’, {

    method: ‘POST’,
    body: imageFormData
    });
    这个fetch()实现可以支持多个文件:
    let imageFormData = new FormData();
    let imageInput = document.querySelector(“input[type=‘file’][multiple]”);
    for (let i = 0; i < imageInput.files.length; ++i) {

    imageFormData.append(‘image’, imageInput.files[i]);
    }
    fetch(’/img-upload’, {

    method: ‘POST’,
    body: imageFormData
    });
  4. 加载Blob 文件
    Fetch API 也能提供Blob 类型的响应,而Blob 又可以兼容多种浏览器API。一种常见的做法是明确将
    图片文件加载到内存,然后将其添加到HTML图片元素。为此,可以使用响应对象上暴露的blob()方法。
    这个方法返回一个期约,解决为一个Blob 的实例。然后,可以将这个实例传给URL.createObjectUrl()
    以生成可以添加给图片元素src 属性的值:
    const imageElement = document.querySelector(‘img’);
    fetch(‘my-image.png’)
    .then((response) => response.blob())
    .then((blob) => {

    imageElement.src = URL.createObjectURL(blob);
    });
  5. 发送跨源请求
    从不同的源请求资源,响应要包含CORS 头部才能保证浏览器收到响应。没有这些头部,跨源请求会失败并抛出错误。
    fetch(’//cross-origin.com’);
    // TypeError: Failed to fetch
    // No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
    如果代码不需要访问响应,也可以发送no-cors 请求。此时响应的type 属性值为opaque,因此无法读取响应内容。这种方式适合发送探测请求或者将响应缓存起来供以后使用。
    fetch(’//cross-origin.com’, { method: ‘no-cors’ })
    .then((response) => console.log(response.type));
    // opaque
  6. 中断请求
    Fetch API 支持通过AbortController/AbortSignal 对中断请求。调用AbortController.
    abort()会中断所有网络传输,特别适合希望停止传输大型负载的情况。中断进行中的fetch()请求会
    导致包含错误的拒绝。
    let abortController = new AbortController();
    fetch(‘wikipedia.zip’, { signal: abortController.signal })
    .catch(() => console.log(‘aborted!’);
    // 10 毫秒后中断请求
    setTimeout(() => abortController.abort(), 10);
    // 已经中断

24.5.3 Headers 对象

Headers 与Map 类型都有get()、set()、has()和delete()
等实例方法,如下面的代码所示:
let h = new Headers();
let m = new Map();
// 设置键
h.set(‘foo’, ‘bar’);
m.set(‘foo’, ‘bar’);
// 检查键
console.log(h.has(‘foo’)); // true
console.log(m.has(‘foo’)); // true
console.log(h.has(‘qux’)); // false
console.log(m.has(‘qux’)); // false
// 获取值
console.log(h.get(‘foo’)); // bar
console.log(m.get(‘foo’)); // bar
// 更新值
h.set(‘foo’, ‘baz’);
m.set(‘foo’, ‘baz’);

24.6 Beacon API

在unload 事件触发时,分析工具要停止收集信息并把收集到的数据发给服务器。这时候有一个问题,
因为unload 事件对浏览器意味着没有理由再发送任何结果未知的网络请求(因为页面都要被销毁了)。
例如,在unload 事件处理程序中创建的任何异步请求都会被浏览器取消。为此,异步XMLHttpRequest
或fetch()不适合这个任务。分析工具可以使用同步XMLHttpRequest 强制发送请求,但这样做会导
致用户体验问题。浏览器会因为要等待unload 事件处理程序完成而延迟导航到下一个页面。
为解决这个问题,W3C 引入了补充性的Beacon API。这个API 给navigator 对象增加了一个
sendBeacon()方法。这个简单的方法接收一个URL 和一个数据有效载荷参数,并会发送一个POST
请求。可选的数据有效载荷参数有ArrayBufferView、Blob、DOMString、FormData 实例。如果请
求成功进入了最终要发送的任务队列,则这个方法返回true,否则返回false。
可以像下面这样使用这个方法:
// 发送POST 请求
// URL: ‘https://example.com/analytics-reporting-url’
// 请求负载:’{foo: “bar”}’
navigator.sendBeacon(‘https://example.com/analytics-reporting-url’, ‘{foo: “bar”}’);
这个方法虽然看起来只不过是POST 请求的一个语法糖,但它有几个重要的特性。
 sendBeacon()并不是只能在页面生命周期末尾使用,而是任何时候都可以使用。
 调用sendBeacon()后,浏览器会把请求添加到一个内部的请求队列。浏览器会主动地发送队
列中的请求。
 浏览器保证在原始页面已经关闭的情况下也会发送请求。
 状态码、超时和其他网络原因造成的失败完全是不透明的,不能通过编程方式处理。
 信标(beacon)请求会携带调用sendBeacon()时所有相关的cookie

Web Sockets

let socket = new WebSocket(“ws://www.example.com/server.php”);
let stringData = “Hello world!”;
let arrayBufferData = Uint8Array.from([‘f’, ‘o’, ‘o’]);
let blobData = new Blob([‘f’, ‘o’, ‘o’]);
socket.send(stringData);
socket.send(arrayBufferData.buffer);
socket.send(blobData);
socket.onmessage = function(event) {

let data = event.data;
// 对数据执行某些操作
};

安全

CSRF(Cross-Site Request Rorgery)
跨站点请求伪造

高级技巧

过程的方式
面向对象的方式

惰性载入函数

        function createXHR() { 

if (typeof XHRHttpRequest != "undefined") { 

return new XHRHttpRequest()
} else if (typeof ActiveXObject != "undefined") { 

} else { 

throw new Error("")
}
}
//一次支持后便永久支持
function createXHR() { 

if (typeof XHRHttpRequest != "undefined") { 

createXHR = function () { 

return new XHRHttpRequest()
}
} else if (typeof ActiveXObject != "undefined") { 

} else { 

createXHR = function () { 

throw new Error("")
}
}
}

函数绑定

在指定this环境中以指定参数调用另一个函数
常常和回调函数和事件处理程序一起使用,将函数作为变量使用的同时保留代码的执行环境

被绑定函数比普通函数相比有更多的开销,需更多的内存,比=因多重函数调用稍微慢些

函数柯里化

函数节流

某些代码不可以在没间断的情况下连续重复执行。
第一次调用函数时,创建一个定时器,在指定时间间隔后运行代码。第二次调用时会清除前一次的定时器并设置另一个。如前一个定时器已执行过了,这个操作就没有意义了。如前一个定时器未执行,将其替换为一个新的定时器。

   var processor={ 

timeoutId:null,
performProcessing:()=>{ 

console.log(1)
},
//不可用箭头函数,
process:function (){ 

clearTimeout(this.timeoutId)
var that=this
//setTimeout中函数的环境是window
this.timeoutId=setTimeout(function (){ 

that.performProcessing()
},200)
}
}
window.onscroll=window.onscroll=()=>{ 

processor.process()}

不是每隔100ms触发一次,而是停止触发超过100ms后触发一次。

//参数:要执行的函数,作用域,没给出作用域在全局作用域中执行
function throttle(method,context){ 

clearTimeout(method.tId)
method.tId=setTimeout(function(){ 

method.call(context)
},100)
}

自定义事件

观察者模式
创建一个管理事件的对象,让其他对象监听那些事件


function EventTarget(){ 

//储存媒体类型
this.handlers={ 
}
}
EventTarget.prototype={ 

constructor:EventTarget,
//注册给定类型事件的事件处理程序
addHandler:function(type,handler){ 

if(typeof this.handlers[type] == "undefined"){ 

this.handlers[type]=[]
}
this.handlers[type].push(handler)
},
//触发一个事件
fire:function(event){ 

if(!event.target){ 

}
},
//注销事件处理程序
removeHandler:function(type,handler){ 

if(this.handlers[type] instanceof Array){ 

var handlers=this.handlers[type]
for(var i=0,len=handlers.length;i<len;i++){ 

if(handlers[i] ===handler){ 

break
}
}
handlers.splice(i,1)
}
}
}

拖放

绝对定位
在这里插入图片描述

25.离线应用和客户端储存

离线检测

navigator.onLine属性

online事件
网络从离线变为在线

offline事件

应用缓存

manifest

数据储存

Cookie

cookie的构成

名称
一个唯一确定的cookie名称,必须被url编码


储存在cookie中的字符串值,必须被url编码


对哪个域是有效的,所有向该域发送的请求都会包含这个cookie

路径
对指定域中的那个路径,应向服务器发送coolie

失效时间
何时应被删除

安全标识
SSL

JS中的cookie

document.cookie
返回一系列;分割的名值对
decodeURLComponent()解码

document.cookie=“name=cc;domain=.www.com;path=/”

//基本cookie操作:读取,写入,删除

25.2 Web Storage

26. 模块

详细介绍

27. 工作者线程

详细介绍

28. 最佳实践

详细介绍

附录 A ES2018 和 ES2019

详细介绍

附录 B 严格模式

详细介绍

附录 C ES2018 和 ES2019

详细介绍

附录 D ES2018 和 ES2019

详细介绍

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/171230.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号