JS学习笔记-202207

目录

参考书籍:《JavaScript高级程序设计(第4版)》马特·弗里斯比

数据类型(基本类型、引用类型)

数据类型

Undefined

Null

Boolean

Number

String

Symbol

Object

引用类型

Date

RegExp

原始值包装类型

单例内置对象

Object

Array

定型数组

Map

WeakMap

Set

WeakSet

js内置数据类型的常用方法及属性

继承

原型链

盗用构造函数

组合继承

原型式继承

寄生式继承

寄生式组合继承

作用域&作用域链

执行上下文

作用域链

作用域链增强

变量声明

使用var的函数作用域声明

使用let的块级作用域声明

使用const的常量声明

标识符查找

DOM

节点层级

Node类型

Document类型

Element类型

Text类型

Comment类型

CDATASection类型

DocumentType类型

DocumentFragment类型

Attr类型

DOM编程

动态脚本

动态样式

操作表格

使用NodeList

MutationObserver接口

基本用法

MutationObserverInit与观察范围

异步回调与记录队列

记录队列

takeRecords()方法

性能、内存与垃圾回收

MutationObserver的引用

MutationRecord的引用

ES6+的语法

Promise 对象

Promise的含义

基本用法

Promise.prototypr.then()

Promise.prototypr.catch()

Promise.prototypr.finally()

Promise.all()

Promise.race()

Promise.allSettled()

Promise.any()

Promise.resolve()

Promise.reject()

应用

Promise.try()


数据类型(基本类型、引用类型)

6种简单数据类型(Undefined、Null、Boolean、Number、String、Symbol)+1种复杂数据类型(Object)

Typeof操作符确定任意变量的数据类型 console.log(typeof 变量名)

数据类型

Undefined

特殊值undefin,声明未初始化的变量为undefined值。

Null

特殊值null,表示一个空对象指针。

(用==比较null和undefined始终返回true。但二者用途不一样:不必显式地将变量值设置为undefined。变量要保存对象但当时又没有对象可保存,用null来填充该变量。这样就可以保持null是空对象指针的语义,并进一步将其与undefined区分开来。)

JS中==和===的区别

Boolean

true和false(True和False是有效标识符,不是布尔值),调用Boolean()转型函数将其它类型的值转换为布尔值。

Number

整数和浮点数。

八进制0?,十六进制0x?。

小数点后没有数的浮点数自动转换为整数。

浮点值计算不精确,不要测试某个特定的浮点值。

科学技术法(浮点数e幂数)

isFinite()函数检验数是否有限大。

NaN表示“不是数值”,不等于包括NaN在内的任何值。isNaN()函数判断是否“不是数值”。

数值转换:Number()、paeseInt()、parseFloat()

String

0或多个16位Unicode字符序列

length属性获取长度

toString()、String()、+””转换为字符串

模板字面量:保留换行字符,可跨行定义字符串,字符串插值${},标签函数自定义插值行为,String.raw标签函数获取原始的模板字面量内容

Symbol

符号使用 Symbol()函数初始化,创建Symbol()实例并将其用作对象的新属性,可以保证它不会覆盖已有的对象属性。

Symbol()不能用作构造函数,与new关键字一起用,避免创建符号包装对象。借用Object()函数使用符号包装对象。

全局符号注册表,用一个字符串作为键,在全局符号注册表中创建并重用符号。Symbol.for()创建新符号(和Symbol()定义的相同符号不等同)。Symbol.KeyFor()查询全局注册表。

Object.getOwnPropertyName()返回对象实例的常规属性数组,Object.getOwnPropertySymbols()返回对象实例的符号属性数组。Object.getOwnPropertyDescriptors()返回同时包含常规和符号属性描述符的对象,Reflect.ownKeys()返回两种类型的键。

常用内置符号:Symbol.asynIterator、Symbol.hasInstance、Symbol.is ConcatSpreadable、Symbol.iterator、Symbol.match、Symbol.replace、Symbol.search、Symbol.species、Symbol.split、Symbol.toStringTag、Symbol.unscopables

Object

一组数据和功能的集合

引用类型

Date

let now=new Date()//保存当前日期和时间

Date.parse()接收表示日期的字符串参数,Date.UTC()接收年、零起点月数、日、时、分、秒、毫秒。Date.now()返回表示执行时日期和时间的毫米数。

toLocalString()返回与浏览器的本地环境一致的日期和时间,toString()返回带时区信息的日期和时间,value()返回日期的毫秒表示。

日期格式化方法:toDateString()、toTimeString()、toLocalDateString()、toLocalTimeString()、toUTCString()

RegExp

通过RegExp类型支持正则表达式

let expression /pattern/flags;//使用字面量形式定义 
let pattern=new RegExp("[bc]at","i");//使用RegExp构造函数来创建

exec()用于配合捕获组使用,test()检验输入的文本与模式是否匹配。

toString()和toLocalString()返回字面量的形式,valueOf()返回正则表达式本身。

析造函数属性(静态):input、lastMatch、lastParen、leftContext、rightContext。

原始值包装类型

1.Boolean

let booleanObject=new Boolean(true);//创建Boolean对象并传入true

2.Number

let numberObject=new Number(10);//创建Number对象并传入10

toFixed()返回包含指定小数点位数的数值字符串

toExponential()返回科学计数法表示的数值字符串

toPrecision()返回最合理的输出结果

isInteger()用于辨别一个数值是否保存为整数

3.String

let stringObject=new String("hello world1");//创建S停对象并传入hello world

charAt()返回给定索引位置的字符

charCodeAt()查看指定码元的字符编码

fromCharCode()根据给定的码元创建字符串中的字符

normalize()判断字符串是否规范化

concat()拼接字符串

slice()、substr()、sunstring()从字符串中提取自字符串

indexOf()、lastIndexOf()在字符串中定位子字符串

startsWith()、endsWitch()、incudes()判断字符串中是否包含另一个字符串

trim()、trimLeft()、trimRight()创建字符串副本并删除空格

repeat()负值字符串并拼接

padStart()、padEnd()复制字符串并填充

toLowerCase()、toLocaleLowerCase()、toUpperCase()、toLocaleUpperCase()大小写转换

match()、search()、replace()、split()字符串模式匹配

localCompare()比较两个字符串

单例内置对象

1.Global

encodeURL()、encodeURLComponent()、decodeURL()、decodeURLComponent() URL编码解码

eval() ECMAScript解释器

2.Math

min()、max()

Math.ceil()、Math.floor()、Math.round()、Math.fround() 舍入

random() 0~1随机数

Object

Array

let colors=new Array("red","blue");//使用Array构造函数创建数组 
let colors=["red","blue"];//使用数组字面量创建数组

from()将类数组结构转换为数组实例,of()将参数转换为数组实例

数组字面量初始化数组时可以使用逗号来创建空位

length可以从数组末尾删除或添加元素

Array.isArray()确定一个值是否为数组

key()、values()、entries()检索数组内容

copyWithin()批量复制

fill()填充数组

valueOf()返回数组本身

toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串

toLocalString()返回一个逗号分隔的数组值的字符串

栈:push()接收参数并将其添加到数组末尾;pop()返回数组最后一项

队列:shift()删除数组的第一项;pop();unshift()在数组开头添加数组

reverse()、sort()排序

concat()在现有数组全部元素基础上创建一个新数组,用Symbol.isConcat-Spreadable阻止打平参数数组。

slice()创建一个包含原有数组中一个或多个原色的新数组

splice()在数组中间插入元素(删除、插入、替换)

严格相等的搜索:indexOf()、includes()从前向后搜索;lastIndexOf()从后向前搜索

断言函数:find()返回第一个匹配元素;findIndex()返回第一个匹配元素的索引

迭代方法:every()、filter()、forEach()、map()、some()

归并方法:reduce()从数组第一项遍历到最后一项;reduceRight()从最后一项遍历到第一项

定型数组

1.ArrayBuffer

ArrayBuffer()用于在内存块中分配特定数量的字节空间

一经创建就不能再调整大小

要读取或写入ArrayBuffer,必须通过视图

2.DateView

允许读写ArrayBuffer的视图,专为文件I/O和网络I/O设计

读写时指定ElementType

支持大端字序和小端字序

读写前提是必须有充足的缓冲区,否则会抛出RangeError

3.定型数组

特定于一种ElementType且遵循系统原生的字节序

创建定型数组:读取已有的缓冲;使用自有缓冲;填充可迭代结构;填充基于任意类型的定型数组;通过<ElementType>.from()和<ElementType>.of()创建。

BYTES_PER_ELEMENT属性返回该类型数组中每个元素的大小

合并、复制和修改定型数组:set()从提供的数组或定型数组中把值复制到当前定型数组中指定的索引位置;subarray()基于从原始定型数组中复制的值返回一个新定型数组。

上溢和下溢:定型数组对于可以存储的每个索引只接受一个相关位,不考虑它们对实际数值的影响。

Map

const m=new Map();
//创建一个空映射,想在创建的同时初始化实例,可以给Map构造函数传入一个可迭代对象,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中

set()添加键/值对;get()、has()查询;size()获取键/值对数量;delete()、clear()删除值

entries()取得迭代器;forEach(calback,opt_thisArg)传入回调

key()、values()返回以插入顺序生成键和值的迭代器

WeakMap

const wm=new weakMap();
//使用new关键字实例化一个空的WeakMap,如果想在初始化时填充弱映射,则构造函数可以接收一个可迭代对象,其中需要包含键/值对数组。可迭代对象中的每个键/值都会按照迭代顺序插入新实例中

弱映射中的键只能是Object或者继承自Object的类型,尝试使用非对象设置键会抛出TypeError。

set()添加键/值对;get()、has()查询delete()删除值

removeReference()摧毁对象的最后一个引用

Set

const m = new Set();
//使用new关键字和Set构造函数创建一个空集合,如果想在创建的同时初始化实例,则可以给Set构造函数传入一个可迭代对象,其中需要包含插入到新集合实例中的元素

add()增加值;has()查询;size()取得元素数量;delete()、clear()删除元素

values()及其别名方法key()、Symbol.iterator取得迭代器

entries()返回迭代器;forEach()传入回调

WeakSet

const ws = new WeakSet();
//使用new关键字实例化一个空的WeakSet;想在初始化时填充弱集合,则构造函数可以接收一个可迭代对象,其中需要包含有效的值。可迭代对象中的每个值都会按照迭代顺序插入到新实例中

弱集合中的值只能是Object或者继承自Object的类型,尝试使用非对象设置值会抛出TypeError。 add()增加值;has()查询;delete()删除元素

removeReference()摧毁对象的最后一个引用

js内置数据类型的常用方法及属性

继承

原型链

任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。

确定原型与实例的关系:使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true;使用isPrototypeOf()方法,只要原型链中包含这个原型,这个方法就返回true。

子类有时候需要覆盖父类的方法,或者增加父类没有的方法。为此,这些方法必须在原型赋值之后再添加到原型上。

以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链。

原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会定义在原型上的原因。在使用原型实现继承时,原型实际上变成了另一个类型的实例。这意味着原先的实例属性摇身一变成为了原型属性。

子类型在实例化时不能给父类型的构造函数传参。

盗用构造函数

在子类构造函数中调用父类构造函数

使用apply()和call()方法以新创建的对象为上下文执行构造函数

可以在子类构造函数中向父类构造函数传参

必须在构造函数中定义方法,因此函数不能重用

组合继承

基本思路:使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。

保留了instanceeof操作符和isPrototyprOf()方法识别合成对象的能力

效率问题:父类构造函数始终会被调用两次,创建子类原型时和在字楼构造函数中调用

原型式继承

function object(o) { function F() {} F.prototype = o; return new F(); 
}//这个object()函数会创建一个临时构造函数,将传入的对象赋值给这个构造函数的原型,然后返回这个临时类型的一个实例。本质上,object()是对传入的对象执行了一次浅复制。

Object.create()方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)

适合不需要单独创建构造函数,但仍需要在对象间共享信息的场合

属性中包含的引用值始终会在相关对象间共享

寄生式继承

思路:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象

适合主要关注对象,而不在乎类型和构造函数的场景

寄生式组合继承

思路:不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。

function inheritPrototype(subType, superType) 
{
 
 let prototype = object(superType.prototype); // 创建对象 
prototype.constructor = subType; // 增强对象 

subType.prototype = prototype; // 赋值对象 
}

保留了instanceeof操作符和isPrototyprOf()方法识别合成对象的能力

引用类型继承的最佳模式

作用域&作用域链

执行上下文

变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。

每个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上。

上下文中的代码在执行的时候,会创建变量的一个作用域链,这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序

如果上下文是函数,则其活动对象(activation object)用作变量对象。活动对象最初只有一个定义变量:arguments。(全局上下文中没有这个变量。)

作用域链

作用域链中的下一个变量对象来自包含上下文,再下一个对象来自再下一个包含上下文。以此类推直至全局上下文;全局上下文的变量对象始终是作用域链的最后一个变量对象。

代码执行时的标识符解析是通过沿作用域链逐级搜索标识符名称完成的。搜索过程始终从作用域链的最前端开始,然后逐级往后,直到找到标识符。(如果没有找到标识符,那么通常会报错。)

每个上下文都可以到上一级上下文中去搜索变量和函数,但任何上下文都不能到下一级上下文中去搜索。

作用域链增强

在作用域链前添加一个变量对象:

        with语句,向作用域链前端添加指定的对象

        try/catch语句的catch块,创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明

变量声明

使用var的函数作用域声明

在使用var声明变量时,变量会被自动添加到最接近的上下文

如果变量未经声明就被初始化了,那么它就会自动被添加到全局上下文

var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作“提升”(hoisting)。提升让同一作用域中的代码不必考虑变量是否已经声明就可以直接使用。

使用let的块级作用域声明

let的作用域是块级的,块级作用域由最近的一对包含花括号{}界定。

同一作用域内不能声明两次。重复的var声明会被忽略,而重复的let声明会抛出SyntaxError。

let的行为适合在循环中声明迭代变量,使用var声明的迭代变量会泄漏到循环外部

let在JavaScript运行时中也会被提升,但由于“暂时性死区”(temporal dead zone)的缘故,实际上不能在声明之前使用let变量。

使用const的常量声明

使用const声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值。

const声明只应用到顶级原语或者对象。赋值为对象的const变量不能再被重新赋值为其他引用值,但对象的键则不受限制。

使用Object.freeze()让整个对象都不能修改,这样再给属性赋值时虽然不会报错,但会静默失败

标识符查找

搜索开始于作用域链前端,以给定的名称搜索对应的标识符。如果在局部上下文中找到该标识符,则搜索停止,变量确定;如果没有找到变量名,则继续沿作用域链搜索。

如果局部上下文中有一个同名的标识符,那就不能在该上下文中引用父上下文中的同名标识符

DOM

文档对象模型(DOM,Document Object Model)是 HTML 和 XML 文档的编程接口。DOM 表示 由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分

节点层级

document 节点表示每个文档的根节点。根节点的唯一子节点是<html>元素,称之为文档元素(documentElement)。文档元素是文档最外层的元素,所有其他元素都存在于这个元素之内。每个文档只能有一个文档元素。在 HTML 页面中,文档元素始终是<html>元素。 HTML 中的每段标记都可以表示为这个树形结构中的一个节点。元素节点表示 HTML 元素,属性节点表示属性,文档类型节点表示文档类型,注释节点表示注释。DOM 中总共有 12 种节点类型,这些类型都继承一种基本类型。

Node类型

节点类型都继承 Node 类型

每个节点都有 nodeType 属性,表示该节点的类型。

节点类型可通过与常量比较来确定

1.nodeName和nodeValue

对元素而言,nodeName 始终等于元素的标签名,而nodeValue 则始终为null

2.节点关系

每个节点都有一个 childNodes 属性,其中包含一个NodeList的实例。NodeList 是一个类数组对象,用于存储可以按位置存取的有序节点,是一个对DOM结构的查询,因此 DOM结构的变化会自动地在 NodeList 中反映出来。

//使用中括号或使用 item()方法访问 NodeList 中的元素 
let firstChild = someNode.childNodes[0]; 
let secondChild = someNode.childNodes.item(1); 
let count = someNode.childNodes.length;//length 属性表示这一时刻NodeList中节点的数量

每个节点都有一个parentNode属性,指向其DOM树中的父元素。

使用 previousSibling和nextSibling可以在列表的节点间导航。

 

haschildNodes()如果返回true则说明节点有一个或多个子节点

ownerDocument 属性,一个指向代表整个文档的文档节点的指针。

3.操纵节点

appendChild()用于在 childNodes 列表末尾添加节点,返回新添加的节点。如果把文档中已经存在的节点传给appendChild(),则这个节点会从之前的位置被转移到新位置。

insertBefore()把节点放到childNodes中的特定位置而不是末尾。 接收两个参数:要插入的节点和参照节,要插入的节点会变成参照节点的前一个同胞节点,并被返回。

replaceChild()接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。

removeChild()移除节点。接收一个参数,即要移除的节点,被移除的节点会被返回。

4.其他方法

cloneNode()返回与调用它的节点一模一样的节点。在传入true参数时,会进行深复制即复制节点及其整个子DOM树。传入 false则只会复制调用该方法的节点。

normalize()处理文档子树中的文本节点。在节点上调用 normalize()方法会检测这个节点的所有后代,如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。

Document类型

Document 类型是表示文档节点的类型。在浏览器中,文档对象document是HTMLDocument的实例(HTMLDocument 继承 Document),表示整个 HTML 页面。document是window对象的属性,因此是一个全局对象。

最常用的是通过 HTMLDocument 的实例取得 document 对象。document 对象可用于获取关于页面的信息以及操纵其外观和底层结构

1.文档子节点

documentElement属性始终指向HTML页面中的<html>元素

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

Document类型另一种子节点是 DocumentType。<!doctype>标签是文档中独立的部分,其信息可以通过doctype属性来访问

严格来讲出现在<html>元素外面的注释也是文档的子节点

2.文档信息

title包含<title>元素中的文本,通常显示在浏 览器窗口或标签页的标题栏。通过这个属性可以读写页面的标题,修改后的标题也会反映在浏览器标题 栏上。修改 title 属性并不会改变<title>元素。

URL包含当前页面的完整URL(地址栏中的URL)

domain包含页面的域名,一旦放松就不能再收紧

当页面中包含来自某个不同子域的窗格(<frame>)或内嵌窗格(<iframe>)时,设置 document.domain 是有用的。因为跨源通信存在安全隐患,所以不同子域的页面间无法通过 JavaScript 通信。此时,在每个页面上把 document.domain 设置为相同的值,这些页面就可以访问对方的 JavaScript 对象了。

referrer包含链接到当前页面的那个页面的 URL。如果当前页面没有来源,则referrer属性包含空字符串

3.定位元素

getElementById()接收要获取元素的 ID(区分大小写),如果找到了则返回这个元素,如果没找到则返回 null。如果页面中存在多个具有相同ID的元素,则返回文档中出现的第一个元素。

getElementsByTagName()接收一个参数,即要 获取元素的标签名,返回包含零个或多个元素的NodeList。在HTML文档中,这个方法返回一个HTMLCollection 对象。要取得文档中的所有元素,可以给 getElementsByTagName()传入*。

namedItem()可通过标签的name属性取得某一项的引用。

getElementsByName()返回具有给定name属性的所有元素。最常用于单选按钮,因为同一字段的单选按钮必须具有相同的name属性才能确保把正确的值发送给服务器

4.特殊集合

document.anchors包含文档中所有带name属性的<a>元素。 document.applets包含文档中所有<applet>元素 document.forms 包含文档中所有<form>元素(与 document.getElementsByTagName ("form") 返回的结果相同)。 document.images 包含文档中所有<img>元素(与 document.getElementsByTagName ("img") 返回的结果相同)。 document.links 包含文档中所有带 href 属性的<a>元素

以上都是实时更新

5.DOM兼容性检测

document.implementation 属性是一个对象,其中提供了与浏览器 DOM 实现相关的信息和能力。 hasFeature()接收两个参数:特性名称和 DOM 版本。如果浏览器支持指定的特性和版本,则hasFeature()方法返回 true,

6.文档写入

向网页输出流中写入内容:write()、writeln()、open()和 close()。其中,write()和 writeln()方法都接收一个字符串参数,可以将这个字符串写入网页中。write()简单地写入文本,而 writeln()还会在字符串末尾追加一个换行符 (\n)。

如果是在页面加 载完之后再调用 document.write(),则输出的内容会重写整个页面

open()和close()方法分别用于打开和关闭网页输出流。在调用 write()和 writeln()时,这两个方法都不是必需的

Element类型

Element表示XML或HTML 元素,对外暴露出访问元素标签名、子节点和属性的能力

可以通过 nodeName 或 tagName 属性来获取元素的标签名。(在HTML中元素标签名始终以全大写表示)

1.HTML元素

所有 HTML 元素都通过 HTMLElement 类型表示,包括其直接实例和间接实例。

标准属性:

id,元素在文档中的唯一标识符; title,包含元素的额外信息,通常以提示条形式展示; lang,元素内容的语言代码(很少用); dir,语言的书写方向("ltr"表示从左到右,"rtl"表示从右到左,同样很少用); className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字, 所以不能直接用这个名字)。

2.取得属性

与属性相关的DOM方法:getAttribute()、setAttribute()和 removeAttribute()

getAttribute()也能取得不是HTML语言正式属性的自定义属性的值,属性名不区分大小写

style和事件处理程序(或者事件属性,比如onclick)通过DOM对象访问的属性中有两个返回的值跟使用 getAttribute()取得的值不一样。

3.设置属性

setAttribute()接收两个参数:要设置的属性名和属性的值。如果属性已经存在,则setAttribute()会以指定的值替换原来的值;如果属性不存在,则 setAttribute()会以指定的值创建该属性。

适用于自定义属性,设置的属性名会规范为小写形式

removeAttribute()从元素中删除属性,不单单是清除属性的值,而是会把整个属性完全从元素中去掉

4.attributes属性

Element 类型是唯一使用 attributes 属性的 DOM 节点类型。attributes 属性包含一个NamedNodeMap实例,是一个类似 NodeList 的“实时”集合。

元素的每个属性都表示为一个Attr节点,并保存在这个NamedNodeMap对象中。

NamedNodeMap对象包含下列方法:

        getNamedItem(name),返回 nodeName 属性等于 name 的节点;

        removeNamedItem(name),删除 nodeName 属性等于 name 的节点;

        setNamedItem(node),向列表中添加 node 节点,以其 nodeName 为索引;

        item(pos),返回索引位置 pos 处的节点。

attributes 属性中的每个节点的 nodeName 是对应属性的名字,nodeValue 是属性的值

let id = element.attributes.getNamedItem("id").nodeValue; 
let id = element.attributes["id"].nodeValue;//中括号访问属性的简写形式 
element.attributes["id"].nodeValue = "someOtherId";//设置属性的值,即先取得属性节点,再将其 nodeValue 设置为新值

setNamedItem()接收一个属性节点,然后给元素添加一个新属性

attributes属性最有用的场景是需要迭代元素上所有属性的时候。这时候往往是要把DOM结构序列化为XML或HTML字符串。

5.创建元素

document.createElement()创建新元素。接收一个参数,即要创建元素的标签名。(HTML文档中标签名不区分大小写)

使用 createElement()方法创建新元素的同时也会将其ownerDocument属性设置为document。

在新元素上设置这些属性只会附加信息。因为这个元素还没有添加到文档树,所以不会影响浏览器显示。要把元素添加到文档树,可以使用 appendChild()、insertBefore()或 replaceChild()。

6.元素后代

元素可以拥有任意多个子元素和后代元素,childNodes属性包含元素所有的子节点,这些子节点可能是其他元素、文本节点、注释或处理指令

要取得某个元素的子节点和其他后代节点,可以使用元素的 getElementsByTagName()方法。在 元素上调用这个方法与在文档上调用是一样的,只不过搜索范围限制在当前元素之内,即只会返回当前 元素的后代。

Text类型

Text节点由Text 类型表示,包含按字面解释的纯文本,也可能包含转义后的 HTML 字符,但不含 HTML 代码。

Text 节点中包含的文本可以通过 nodeValue 属性访问,也可以通过 data 属性访问,这两个属性包含相同的值。修改 nodeValue 或 data 的值,也会在另一个属性反映出来。

文本节点暴露了以下操 作文本的方法:

        appendData(text),向节点末尾添加文本 text;

        deleteData(offset, count),从位置 offset 开始删除 count 个字符;

        insertData(offset, text),在位置 offset 插入 text;

        replaceData(offset, count, text),用 text 替换从位置 offset 到 offset + count 的文本;

        splitText(offset),在位置 offset 将当前文本节点拆分为两个文本节点;

        substringData(offset, count),提取从位置 offset 到 offset + count 的文本。

通过length属性获取文本节点中包含的字符数量。这个值等于nodeValue.length和data.length。

默认情况下,包含文本内容的每个元素最多只能有一个文本节点

let textNode = div.firstChild; // 访问这个文本节点,或div.childNodes[0] 
div.firstChild.nodeValue = "Some other message";//取得文本节点的引用后,这样来修改它

HTML或XML代码(取决于文档类型)会被转换成实体编码,即小于号、大于号或引号会被转义

1.创建文本节点

document.createTextNode()创建新文本节点,接收一个参数,即要插入节点的文本。

创建新文本节点后,其 ownerDocument 属性会被设置为 document。

在将一个文本节点作为另一个文本节点的同胞插入后,两个文本节点的文本之间不会包含空格。

2.规范化文本节点

normalize(),是在 Node 类型中定义的(因此所有类型的节点上都有这个方法)。在包含两个或多个相邻文本节点的父节点上调用 normalize()时,所有同胞文本节点会被合并为一个文本节点,这个文本节点的 nodeValue 就等于之前所有同胞节点 nodeValue 拼接在一起得到的字符串

3.拆分文本节点

splitText()在指定的偏移位置拆分 nodeValue,将一个文本节点拆分成两个文本节点。拆分之后,原来的文本节点包含开头到 偏移位置前的文本,新文本节点包含剩下的文本。这个方法返回新的文本节点,具有与原来的文本节点 相同的 parentNode。

最常用于从文本节点中提取数据的 DOM 解析技术。

Comment类型

DOM 中的注释通过 Comment 类型表示。

Comment 类型与Text类型继承同一个基类(CharacterData),因此拥有除 splitText()之外Text节点所有的字符串操作方法。与 Text 类型相似,注释的实际内容可以通过 nodeValue 或 data 属性获得。

注释节点可以作为父节点的子节点来访问。

document.createComment()方法创建注释节点,参数为注释文本

如果要访问注释节点,则必须确定它们是<html>元素的后代。

CDATASection类型

CDATASection 类型表示 XML 中特有的 CDATA 区块。CDATASection 类型继承 Text 类型,因 此拥有包括 splitText()在内的所有字符串操作方法

在真正的 XML 文档中,使用document.createCDataSection()并传入节点内容来创建 CDATA区块

DocumentType类型

DocumentType类型的节点包含文档的文档类型(doctype)信息

DocumentType对象保存在 document.doctype 属性中。

DocumentType对象的3个属性:name、entities和notations。name是文档类型的名称,entities是这个文档类型描述的实体的NamedNodeMap,notations是这个文档类型描述的表示法的NamedNodeMap。

DocumentFragment类型

DocumentFragment类型是唯一一个在标记中没有对应表示的类型。DOM 将文档片段定义为“轻量级”文档,能够包含和操作节点,却没有完整文档那样额外的消耗。

不能直接把文档片段添加到文档。文档片段的作用是充当其他要被添加到文档的节点的仓库。 document.createDocumentFragment()创建文档片段

文档片段从 Node 类型继承了所有文档类型具备的可以执行 DOM 操作的方法。

如果文档中的一个节点被添加到一个文档片段,则该节点会从文档树中移除,不会再被浏览器渲染。添加到文档片段的新节点同样不属于文档树,不会被浏览器渲染。

appendChild()或insertBefore()方法将文档片段的内容添加到文档。

在把文档片段作为参数传给这些方法时,这个文档片段的所有子节点会被添加到文档中相应的位置。文档片段本身永远不会被添加到文档树。

Attr类型

元素数据在DOM中通过Attr类型表示。Attr 类型构造函数和原型在所有浏览器中都可以直接访问。技术上讲,属性是存在于元素attributes属性中的节点。

属性节点不被认为是 DOM 文档树的一部分。

Attr节点很少直接被引用,通常使用 getAttribute()、removeAttribute()和 setAttribute()方法操作属性。 Attr对象上有 3个属性:name、value 和 specified。name包含属性名(与nodeName一样),value包含属性值(与nodeValue一样),specified是一个布尔值,表示属性使用的是默认值还是被指定的值。

document.createAttribute()创建新的 Attr 节点,参数为属性名

DOM编程

动态脚本

<script>元素用于向网页中插入 JavaScript 代码,可以是 src 属性包含的外部文件,也可以是作为该 元素内容的源代码。

动态脚本就是在页面初始加载时不存在,之后又通过 DOM 包含的脚本。

与对应的 HTML 元素一样,有两种方式通过<script>动态为网页添加脚本:引入外部文件和直接插入源代码。

通过 innerHTML 属性创建的<script>元素永远不会执行。

动态样式

CSS样式在HTML页面中可以通过两个元素加载。<link>元素用于包含CSS外部文件,而<style> 元素用于添加嵌入样式。

与动态脚本类似,动态样式也是页面初始加载时并不存在,而是在之后才添加 到页面中的。

操作表格

<table>元素添加了以下属性和方法:

        caption,指向<caption>元素的指针(如果存在);

        tBodies,包含<tbody>元素的 HTMLCollection;

        tFoot,指向<tfoot>元素(如果存在);

        tHead,指向<thead>元素(如果存在);

        rows,包含表示所有行的 HTMLCollection;

        createTHead(),创建<thead>元素,放到表格中,返回引用;

        createTFoot(),创建<tfoot>元素,放到表格中,返回引用;

        createCaption(),创建<caption>元素,放到表格中,返回引用;

        deleteTHead(),删除<thead>元素;

        deleteTFoot(),删除<tfoot>元素;

        deleteCaption(),删除<caption>元素;

        deleteRow(pos),删除给定位置的行;

        insertRow(pos),在行集合中给定位置插入一行。

<tbody>元素添加了以下属性和方法:

        rows,包含<tbody>元素中所有行的 HTMLCollection;

        deleteRow(pos),删除给定位置的行;

        insertRow(pos),在行集合中给定位置插入一行,返回该行的引用。

<tr>元素添加了以下属性和方法:

        cells,包含<tr>元素所有表元的 HTMLCollection;

        deleteCell(pos),删除给定位置的表元;

        insertCell(pos),在表元集合给定位置插入一个表元,返回该表元的引用。

使用NodeList

NodeList对象和相关的NamedNodeMap、HTMLCollection都是“实时的”,意味着文档结构的变化会实时地在它们身上反映出来,因此它们的值始终代表最新的状态

任何时候要迭代NodeList,最好再初始化一个变量保存当时查询时的长度,然后用循环变量与这个变量进行比较

最好限制操作 NodeList 的次数。因为每次查询都会搜索整个文档,所以最好把查询到 的 NodeList 缓存起来。

MutationObserver接口

MutationObserver接口可以在DOM被修改时异步执行回调。

使用 MutationObserver可以观察整个文档、DOM 树的一部分,或某个元素。此外还可以观察元素属性、子节点、文本,或者前三者任意组合的变化。

基本用法

//MutationObserver 的实例要通过调用 MutationObserver 构造函数并传入一个回调函数来创建 
let observer = new MutationObserver(() => console.log('DOM was mutated!'));

1.observe()方法

使用observe()方法把MutationObserver的实例observer与DOM关联起来。接收两个必需的参数:要观察其变化的DOM节点,以及一个MutationObserverInit对象。

MutationObserverInit 对象用于控制观察哪些方面的变化,是一个键/值对形式配置选项的字典。

2.回调与MutationRecord

每个回调都会收到一个MutationRecord实例的数组。MutationRecord实例包含的信息包括发生了什么变化,以及DOM的哪一部分受到了影响。

因为回调执行之前可能同时发生多个满足观察条件的事件,所以每次执行回调都会传入一个包含按顺序入队的 MutationRecord 实例的数组。

传给回调函数的第二个参数是观察变化的MutationObserver的实例

3.disconnect()方法

disconnect()提前终止执行回调,同步调用disconnect()之后,不仅会停止此后变化事件的回调,也会抛弃已经加入任务队列要异步执行的回调

setTimeout()让已经入列的回调执行完毕再调用disconnect()

4.复用MutationObserver

多次调用observe()方法,可以复用一个MutationObserver对象观察多个不同的目标节点。此时,MutationRecord的target属性可以标识发生变化事件的目标节点。

调用disconnect()会停止观察所有目标

5.重用MutationObserver

调用disconnect()并不会结束MutationObserver的生命。还可以重新使用这个观察者,再将它关联到新的目标节点。

MutationObserverInit与观察范围

MutationObserverInit 对象用于控制对目标节点的观察范围。

1.观察属性

MutationObserver 可以观察节点属性的添加、移除和修改。

//为属性变化注册回调,需要在MutationObserverInit对象中将attributes属性设置为true 
let observer = new MutationObserver( 
    (mutationRecords) => console.log(mutationRecords)); 
observer.observe(document.body, { attributes: true });

如果想观察某个或某几个属性,可以使用attributeFilter属性来设置白名单,即一个属性名字符串数组

如果想在变化记录中保存属性原来的值,可以将attributeOldValue属性设置为true

2.观察字符数据

MutationObserver可以观察文本节点(如Text、Comment或ProcessingInstruction节点)中字符的添加、删除和修改。要为字符数据注册回调,需要在 MutationObserverInit 对象中将characterData属性设置为 true。

如果想在变化记录中保存原来的字符数据,可以将characterDataOldValue属性设置为true

3.观察子节点

MutationObserver可以观察目标节点子节点的添加和移除。要观察子节点,需要在Mutation-ObserverInit 对象中将 childList 属性设置为 true。

对子节点重新排序(尽管调用一个方法即可实现)会报告两次变化事件,因为从技术上会涉及先移 除和再添加

4.观察子树

默认情况下,MutationObserver将观察的范围限定为一个元素及其子节点的变化。可以把观察的范围扩展到这个元素的子树(所有后代节点),这需要在MutationObserverInit对象中将subtree属性设置为 true。

被观察子树中的节点被移出子树之后仍然能够触发变化事件。这意味着在子树中的节点离开该子树后,即使严格来讲该节点已经脱离了原来的子树,但它仍然会触发变化事件。

异步回调与记录队列

为了在大量变化事件发生时不影响性能,每次变化的信息(由观察者实例决定)会保存在MutationRecord实例中,然后添加到记录队列。这个队列对每个MutationObserver实例都是唯一的,是所有 DOM 变化事件的有序列表。

记录队列

每次MutationRecord被添加到MutationObserver的记录队列时,仅当之前没有已排期的微任务回调时(队列中微任务长度为0),才会将观察者注册的回调(在初始化 MutationObserver 时传入)作为微任务调度到任务队列上。这样可以保证记录队列的内容不会被回调处理两次。

被调用的回调会接收到一个MutationRecord实例的数组,顺序为它们进入记录队列的顺序。回调要负责处理这个数组的每一个实例,因为函数退出之后这些实现就不存在了。回调执行后记录队列会被清空

takeRecords()方法

调用 MutationObserver实例的takeRecords()方法可以清空记录队列,取出并返回其中的所有 MutationRecord实例。

在希望断开与观察目标的联系,但又希望处理由于调用disconnect()而被抛弃的记录队列中的 MutationRecord实例时比较有用。

性能、内存与垃圾回收

MutationObserver的引用

MutationObserver实例与目标节点之间的引用关系是非对称的。MutationObserver拥有对要 观察的目标节点的弱引用,不会妨碍垃圾回收程序回收目标节点。目标节点拥有对MutationObserver 的强引用,如果目标节点从 DOM 中被移除,随后被垃圾回收,则关联的 MutationObserver 也会被垃圾回收。

MutationRecord的引用

记录队列中的每个MutationRecord实例至少包含对已有DOM节点的一个引用。如果变化是childList类型,则会包含多个节点的引用。记录队列和回调处理的默认行为是耗尽这个队列,处理每个MutationRecord,然后让它们超出作用域并被垃圾回收。 有时候可能需要保存某个观察者的完整变化记录。保存这些MutationRecord实例,也就会保存它们引用的节点,因而会妨碍这些节点被回收。如果需要尽快地释放内存,建议从每个MutationRecord中抽取出最有用的信息,然后保存到一个新对象中,最后抛弃MutationRecord。

参考书籍:《ECMAScript 6 入门教程》是一本开源的 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性。

ES6+的语法

Promise 对象

Promise的含义

Promise 是异步编程的一种解决方案,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有两个特点:

        (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

        (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要情况发生,状态不会再变了,这时就称为 resolved(已定型)。如果改变已经发生,你再对Promise对象添加回调函数,也会立即得到这个结果。

Promise对象可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

Promise对象提供统一的接口,使得控制异步操作更加容易。

Promise无法中途取消,一旦新建它就会立即执行。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于pending状态时,无法得知目前进展到哪一个阶段

基本用法

//创造Promise实例 
const promise = new Promise(function(resolve, reject) { // ... some code 
if (/* 异步操作成功 */){ 
    resolve(value); 
} else { 
    reject(error); 
    } 
});

resolve函数的作用是将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用是将Promise对象的状态从“未完成”变为“失败”,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

//用then方法分别指定resolved状态和rejected状态的回调函数。 
promise.then(function(value) {
 // success 
}, function(error) {
 // failure 
});

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。

Promise.prototypr.then()

then方法返回的是一个新的Promise实例。可以采用链式写法,即then方法后面再调用另一个then方法。

getJSON("/posts.json").then(function(json) {
    return json.post; 
}).then(function(post) {
    // ... 
});

Promise.prototypr.catch()

Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
    // ... 
}).catch(function(error) { 
    // 处理 getJSON 和 前一个回调函数运行时发生的错误 
    console.log('发生错误!', error); 
});

上面代码中,getJSON()方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。

如果 Promise状态已经变成resolved,再抛出错误是无效的。

Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。错误总是会被下一个catch语句捕获。

如果没有使用catch()方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。

建议Promise对象后面要跟catch()方法,这样可以处理Promise内部发生的错误。catch()方法返回的还是一个Promise对象,因此后面还可以接着调用then()方法。

Promise.prototypr.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

promise 
.then(result => {···}) 
.catch(error => {···}) 
.finally(() => {···});

finally方法总是会返回原来的值。

Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的Promise实例。

const p = Promise.all([p1, p2, p3]);

p的状态由p1、p2、p3决定

  (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

  (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

如果作为参数的Promise实例自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

Promise.race()

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。

Promise.allSettled()

Promise.allSettled()用来确定一组异步操作是否都结束了(不管成功或失败),接受一个数组作为参数,数组的每个成员都是一个Promise对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的Promise对象才会发生状态变更。

Promise.any()

接受一组Promise实例作为参数,包装成一个新的 Promise 实例返回。

只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

Promise.any()不会因为某个Promise 变成rejected状态而结束,必须等到所有参数Promise变成rejected状态才会结束。

Promise.resolve()

将现有对象转为Promise对象

Promise.resolve()方法的参数分成四种情况

  (1)如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

  (2)参数是一个thenable对象

  thenable对象指的是具有then方法的对象,Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。

Promise.reject()

应用

Promise.try()

时间有限,ES6的坑先占着,之后有时间再补ovo

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值