alioth/before/cha/06===BPEMR/xi-note-computer/Xi-A-Program/Xi-A1-JavaScript/JS/JavaScript高级程序设计(第四版)深入学习.md
2025-05-30 09:18:01 +08:00

31 KiB
Raw Blame History

JavaScript高级程序设计第四版深入学习

2021/6/14

本书出版于2020/9

2019的内容

第1章 什么事JavaScript

1995 网景公司。应对低网速,实现客户端表单验证

我要好好学习!!!

  • ECMAScript
  • DOM
  • BOM

第2章 HTML中的JavaScript

建议使用外部文件

理解加载顺序

延迟和下载完执行

第3章 语言基础

3.1 语法

  • 区分大小写

  • 第一个字母是_和$或者字母(unicode的所有字符包括汉字)

  • 剩下的可以添加数字

  • 关键字、保留子、true、false、null不可以

  • 单行注释和多行注释//。/**/

  • 严格模式,在脚本第一行加入"use strict",这是全局严格模式,函数头部分可以定义整个函数

  • 最好使用分号

  • 最好使用代码块

3.2 保留字和关键字

3.3 变量

3.1 var

var可以在所有版本适用

let const值在ecma6以上

var 作用域在return后销毁

var可以重新赋值也可以重新定义类型但不推荐

省略var定义的是全局变量不推荐严格模式不支持

可以反复定义一个变量,可以在使用后定义(声明提升),但不建议

3.2 let

let相比于varlet作用域是语句块比如在if语句中声明的变量除了if就失效

let不允许多次声明(在子块中可以再次声明)

let和var混用不会报错只是针对不同的应用范围

let不会被提升

全局声明window.关键字只能作用于var的全局变量,let则不行

3.3 const常量

声明时必须赋值

不允许重复声明

不能修改值

和let相似

3.4 数据类型

6种简单类型UndefinedNullBooleanNumberStringSymbolES6

复杂类型Object对象

let a="hello world!";
typeof a;//"string"
typeof(a);//"string"
typeof 32;//"number"


//typeof是一个操作符不是一个函数所以不需要参数但是也可以使用参数

3.4.2 Undefined

let和var未赋值

undefined主要用于比较

未定义和使用未出现的值不一样,未出现的值会报错

let a;
console.log(a);//undefined
console.log(b);//error
console.log(typeof b);//undefined,对于未声明的变量只有一个正确操作符就是typeof
let a;//undefined
if(a)//不执行
if(!a)//执行
if(c)//error

3.4.3 Null

null指空对象

let a=null;
console.log(typeof a);//Object

null用于声明空对象

3.4.4 Boolean值

true!=1

false!=0

区分大小写

转换其他类型

P33

3.4.5 Number

10进制直接输入

8进制在严格模式下不支持一般模式下第一位是零后面有超过基数的会当成十进制

16进制0x区分大小写

3.4.5.1浮点型

允许.11出现但不建议

默认将无效小数部分转化为整数

0.1+0.2=0.300000000004

3.4.5.2范围

最大值Number.MAX_VALUE

最小值Number.MIN_VALUE

Number.NEGATIVE_INFINITY +infinity

Number.POSTTIVE_INFINITY -infinity

3.4.5.3NaN

不是数值,返回操作数值时失败

分母为零时

NaN不参与操作包括if比较

isNaN("32")//isNaN检测函数

3.4.5.4 数值转换

Number()

parseInt()第二个参数可以指定进制parseInt("AF",16)//175

不指定进制需要使用标准进制表示法0xAF

开头必须是数字否则识别为NaN空字符也为NaN

parseFloat()

详细规则P36

3.4.6 String

3.4.6.1字符字面量
\n
\t
\b	退格
\r
\f	换页
\\

转义字符在字符串中算1个字符

3.4.6.2 字符串拼接

同Python

3.4.6.3 转换为字符串

a.toString()//null和undefined没有这个方法

一般不传参和parseInt一样参数代表进制

3.4.6.4模板字面量

换行会出现在字符串中正确表达

方便了HTML

3.4.6.5 字符串插值
`${ a }scac`//这种样式的字符串插值必须使用1旁边的分词号
3.4.6.7 原始字符串,不转义
String.raw'xasxas'
a="xasxax\xasxasx"
a.raw;
console.log(a.raw)

3.4.6Symbol

3.4.7 Object()

let a= new Object();

3.5 操作符

3.6 语句

3.6.1 if

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

}else if(){

}else{

}

3.6.2 do while

do{

}while()

3.6.3while

while(){

}

3.6.4 for语句

for(){

}

3.6.5 for in

for(a in b){
}

3.6.6 for of

for(a of b){}//严格迭代 i of window不行

3.6.7 标签语句

3.6.8 break和continue语句

3.6.9with

将作用域设置给特定对象

with(location){
	let qs=search.substring(1);
	let url=href;
}
//实际上是location.search.substring(1)

3.6.10 switch

和c一样

 switch(){
 	case value:
 		语句
 		break;
 	
 }

3.7 函数

eval和arguments不能出现在函数名称和函数参数中

第4章 变量、作用域和内存

4.1原始值和引用值

原始值不能添加属性,有六个原始值

let a=new String("xs");//这里变成了一哥obj
let b="xsx"
a.name="xs"//这里是错误的,但是不会报错,只是无法输出
b.name="xs"
console.log(a.name)//xs
console.log(b.name)//undefined
console.log(typeof a)//Object
console.log(typeof a)//String

4.1.2 复制值

原始值直接复制

引用值复制的是对象指针,修改原数据,复制值也会改变

4.1.3 函数传参

传参都是按值传参(各自的方式)

原始值和引用值都是通过自己的方式复制过去

4.1.4 确定类型

typeof面对对象或者undefined。 输出的是Object

4.2 执行上下文和作用域

4.2.2 变量声明

1var

自动添加到最近的上下文

2let

块级

3标识符查找

函数面对标识符时先在最近的上下文查找,查找不到在进行上下文查找,如果在最近的查找到了,就不会再运用全局的

4.3 垃圾回收

标记清理

引用计数(有问题已弃用)

4.3.3性能

调度垃圾回收过于频繁会造成性能浪费

4.3.4内存

手动释放

变量=null

多使用 let 和const

隐藏类:用同一个函数初始化,在定义函数时候初始化属性,让新创建的函数隐藏函数保持一致

内存泄漏:没有声明的变量直接赋值,成为全局变量,不会自动回收

第5章 基本引用类型

引用类型不是类

new 构造函数;//创建一个对象

5.1 Date

1970/1/1

let now = new Date();
now=new Date(Date.parse("6/15/2021"));//指定日期
now=new Date("6/15/2021");//同上面,构造函数隐式调用
now=new Date(Date.UTC(2021,0,1,12,5,21))
now=new Date(2021,0,1,12,5,21)//构造函数隐式调用

let starttime=Date.now()
let wndtime=Date.now()

5.1.1 继承的方法

now.toLocaleString();//本地时间
now.toString();//包含时区

5.1.2 日期格式化


now=new Date()
//Date Tue Jun 15 2021 15:53:25 GMT+0800 (中国标准时间)

now.toLocaleString()
//"2021/6/15 下午3:53:25"
now.toDateString()
//"Tue Jun 15 2021"
now.toTimeString()
//"15:53:25 GMT+0800 (中国标准时间)"
now.toLocaleDateString()
//"2021/6/15"
now.toLocaleTimeString()
//"下午3:53:25"
now.toUTCString()
//"Tue, 15 Jun 2021 07:53:25 GMT"

5.1.3 日起时间方法

P106

5.2 RegExp

正则表达式

5.3 原始值包装类型

let str1="i love u!";
let str2=str1.substring(2);//正常逻辑下这是错误的

第二次访问str1的时候以只读模式进行

let str1=new String("i love u!");
let str2=str1.substring(2);
s1=null;

5.3.1 Boolean

let booleantrueobj=new Obiect(true);//这是一个存储布尔值的对象

//因为是对象不管布尔值是什么用对象做比较永远是true

尽量永远不要使用boolean对象

5.3.2 Number

toFixed(2)//指定小数位数

四舍五入

toExponential(2)//指定科学计数法

.toPrecision(5)//数字总位数

Number.isInteger(num);//判断是你不是整数

5.3.3 String

1 JavaScript字符

str.length

charCodeAt()可以查看字符的编码

2 normalize()方法

某些unicode字符有多个遍吗

3 字符串操作方法

常用的str1.slice(起始,-3)

Str1.substring(2) 第二个字符后面的

Str1.substr(-3)

4 字符串位置方法

Str1.indexOf("o",起始位置int)

Str1.lastIndexOf("0",起始位置int)

5

6 trim()删除前后的空格 str1.trim()

7 repeat()赋值几遍str1.repeat(5)//赋值5遍

8 填充

padStart(),padEnd()

字符串超限无法使用

let a="ABCDE"

console.log(a.padStart(10,"*"))
//*****ABCDE debugger eval code:1:9

console.log(a.padEnd(10,"*"))
//ABCDE***** debugger eval code:1:9

9 迭代

for (const c of "abcde") { 
 console.log(c); 
} 

10 字符串大小写转换

let stringValue = "hello world"; 
console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD" 
console.log(stringValue.toUpperCase()); // "HELLO WORLD" 
console.log(stringValue.toLocaleLowerCase()); // "hello world" 
console.log(stringValue.toLowerCase()); // "hello world" 

11

12 localeCompare()方法

比较字符顺序

let a="何";
let b="小";
let c="啊"
a.localeCompare(b);
//-1
b.localeCompare(a)
//1
a.charCodeAt()
20309
b.charCodeAt()
23567
c.charCodeAt()
21834

5.4 单例内置对象

5.4.1Global

1 URL编码方法

将字符替换为编码

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));

将编码替换为字符(只能替换自己支持的字符)

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

2 eval()

将内容加入到上下文中

eval("console.log('hi')"); 
//	上面这行代码的功能与下一行等价:
console.log("hi");

5.4.2 Math

2 min(数组), max(数组)

3 舍入方法

//Math.ceil()方法始终向上舍入为最接近的整数。5.4 单例内置对象 133 
//Math.floor()方法始终向下舍入为最接近的整数。
//Math.round()方法执行四舍五入。
//Math.fround()方法返回数值最接近的单精度32 位)浮点值表示。

4 random()随机数0-1不包括1

5 其他方法

Math.abs(x)绝对值

Math.pow(a,b)a的b次幂

Math.trunc(xx的整数

第6章 集合引用类型

6.1 Object

显式地创建

//第一种是使用 new 操作符和 Object 构造函数
let person = new Object(); 
person.name = "Nicholas"; 
person.age = 29;
//另一种方式是使用  *对象字面量* object literal表示法
let person = { 
 name: "Nicholas", 
 age: 29 
}; 
//在对象字面量表示法中,属性名可以是字符串或数值,比如:
let person = { 
 "name": "Nicholas", 
 "age": 29, 
 5: true //自动将5转化为字符串格式
}; 
//属性一般是通过点语法来存取的,这也是面向对象语言的惯例
//但也可以使用中括号来存取属性。在使用中括号时,要在括号内使用属性名的字符串形式
console.log(person["name"]); // "Nicholas" 
console.log(person.name); // "Nicholas" 

6.2 Array

跟其他语言中的数组一样ECMAScript 数组也是一组有序的数据,但跟其他语言 不同的是,数组中每个槽位可以存储任意类型的数据

6.2.1创建数组

//使用 Array 构造函数
let arr = new Array();
let arr = new Array(20);//长度为20可省略new
let arr= new Array("Hello","World","!");//含有三个可省略new

//使用数组字面量array literal表示法
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个元素的数组
let names = []; // 创建一个空数组
let values = [1,2,]; // 创建一个包含 2 个元素的数组
//与对象一样,在使用数组字面量表示法创建数组不会调用 Array 构造函数

from 和 of

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] 

6.2.2 数组空位

用逗号创建

ES6之前将空位解释为undefined

6.2.3 数组索引

同其他语言但是可以超过长度被解析为undefined

//使用 length 属性可以方便地向数组末尾添加元素,如下例所示:
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors[colors.length] = "black"; // 添加一种颜色(位置 3
colors[colors.length] = "brown"; // 再添加一种颜色(位置 4

数组最多可以包含 4 294 967 295 个元素

6.2.4 检测数组

if (Array.isArray(value)){ 
 // 操作数组
} 

6.2.5 迭代器方法

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

6.2.6 复制和填充方法

//fill()
let arr=[1,2,3,1,4,5,6,5]
arr.fill(填充内容起始结束不包含)
arr.copyWithin(从哪儿开始填充原来文本的开始原来文本的结束不包含)

6.2.7 转化方法

let colors = ["red", "green", "blue"]; 
alert(colors.join(",")); // red,green,blue 
alert(colors.join("||")); // red||green||blue

6.2.8 栈方法

let a=["i","l","o","v","e","u"]
a.push("!");
a.push("w","j","y")
a.pop();//删除并返回同时减少length

6.2.9 队列方法

a.shift();//删除开头并返回;

6.2.10 排序方法

let values = [1, 2, 3, 4, 5]; 
values.reverse();//反响排序,此方法不够灵活
values.sort(); //升序但是先转化为字符串10在5前面

//比较函数
values.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
//同下
function compare(value1, value2) { 
 if (value1 < value2) { 
 return 1; 
 } else if (value1 > value2) { 
 return -1; 
 } else { 
 return 0; 
 } 
} 
let values = [0, 1, 5, 10, 15]; 
values.sort(compare); 
alert(values); // 15,10,5,1,0

6.2.11 操作方法

concat()我感觉可以用append()代替

Slice(a,b);切片可以用负值

splice

  • 删除splice(开始删除的位置,删除的数量)
  • 插入splice(开始位置,删除数量,插入值(后面可以是多个))
  • 替换splice(开始位置删除数量也就是替换为0不替换插入值同上)

6.2.12 搜索和位置方法

1 严格相等

a.indexOf()有返回对象没有返回-1
a.lastIndexOf()有返回对象没有返回-1
a.includes()返回布尔值

6.2.13 迭代

6.2.14 归并方法

6.3 定型数组

6.4 Map

6.4.1 基本API

const m = new Map(); 
alert(m.has("firstName")); // false 
alert(m.get("firstName")); // undefined 
alert(m.size); // 0 
m.set("firstName", "Matt") 
 .set("lastName", "Frisbie"); 
alert(m.has("firstName")); // true 
alert(m.get("firstName")); // Matt 
alert(m.size); // 2 
m.delete("firstName"); // 只删除这一个键/值对
alert(m.has("firstName")); // false 
alert(m.has("lastName")); // true 
alert(m.size); // 1 
m.clear(); // 清除这个映射实例中的所有键/值对
alert(m.has("firstName")); // false 
alert(m.has("lastName")); // false 
alert(m.size); // 0

6.4.2

6.4.3 选择

P168

6.5 WeakMap

6.6 Set

6.7 WeakSet

第7章 迭代器与生成器

第8章 对象、类与面向对象编程

第9章 代理与反射

ECMAScript6 新增

9.1 代理基础

代理是目标对象的抽象 代理类似C++指针 可以用作目标对象的替身、但又完全独立于目标对象。

9.1.1 创建空代理

第10章 函数

函数定义的方法:

  1. 函数声明
function function_name(argument) {
    // body...
    return argument;
};
  1. 函数表达式
let fun=function(a){
    return a;
};

  1. 构造函数
let fun=Function("a","return a");
//所有函数定义都会在最后转化为这种格式

10.1 箭头函数

let fun=(a,b)=>{return a+b;};

10.2 函数名

函数名是指向函数的指针,所以函数可以有多个名称 函数都有一个name属性a.name//a

10.3 理解参数

10.4 没有重载

在js种重复声明函数会覆盖好像还会报错

10.5 默认参数值

function makeKing(name) { 
 name = (typeof name !== 'undefined') ? name : 'Henry'; //如果函数调用时没有参数,默认为。。。
 return `King ${name} VIII`; 
} 


function makeKing(name = 'Henry', numerals = 'VIII') { //多个默认参数
 return `King ${name} ${numerals}`; 
} 
console.log(makeKing()); // 'King Henry VIII' 
console.log(makeKing('Louis')); // 'King Louis VIII'


//箭头函数也可以

  • 默认参数作用域与暂死区
//      参数初始化顺序遵循“暂时性死区”规则,即前面定义的参数不能引用后面定义的。像这样就会抛出错误:
// 调用时不传第一个参数会报错
function makeKing(name = numerals, numerals = 'VIII') { 
 return `King ${name} ${numerals}`; 
} 
//      参数也存在于自己的作用域中,它们不能引用函数体的作用域:
// 调用时不传第二个参数会报错
function makeKing(name = 'Henry', numerals = defaultNumeral) { 
 let defaultNumeral = 'VIII'; 
 return `King ${name} ${numerals}`; 
}

10.6

10.7 函数声明与函数表达式

JavaScript引擎在加载数据时对他们区别对待在任何代码执行钱会先读取函数声明并在执行上下文中生成函数定义而函数表达式必须等到代码执行到它的一行才会在执行上下文中生成函数定义

// 没问题 
console.log(sum(10, 10)); 
function sum(num1, num2) { 
 return num1 + num2; 
}

// 会出错
console.log(sum(10, 10)); 
let sum = function(num1, num2) { 
 return num1 + num2; 
};

10.8 函数作为参数

10.9 函数内部

在 ECMAScript 5 中函数内部存在两个特殊的对象arguments 和 this。ECMAScript 6 又新增 了 new.target 属性。

10.9.1 argments

function factorial(num) { 
 if (num <= 1) { 
 return 1; 
 } else { 
 return num * factorial(num - 1); 
 } 
} 
//阶乘函数

function factorial(num) { 
 if (num <= 1) { 
 return 1; 
 } else { 
 return num * arguments.callee(num - 1); //无论函数名是什么都可以使用arguments.callee()调用
 } 
} 

10.9.2 this

10.9.3 caller

function outer() { 
 inner(); 
} 
function inner() { 
 console.log(inner.caller); 
} 
outer();//会显示outer的源代码
inner();//null

10.10函数属性和方法

每个函数都有两个属性length 和 prototype。其中length 属性保存函数定义的命名参数的个数

function sayName(name) { 
 console.log(name); 
} 
function sum(num1, num2) { 
 return num1 + num2; 
} 
function sayHi() { 
 console.log("hi"); 
} 
console.log(sayName.length); // 1 
console.log(sum.length); // 2 
console.log(sayHi.length); // 0

10.11 函数表达式

10.12 递归

10.14 闭包

10.15 立即调用的函数表达式

使用 IIFE 可以模拟块级作用域即在一个函数表达式内部声明变量然后立即调用这个函数
样位于函数体作用域的变量就像是在块级作用域中一样ECMAScript 5 尚未支持块级作用域使用 IIFE
模拟块级作用域是相当普遍的比如下面的例子
// IIFE 
(function () { 
 for (var i = 0; i < count; i++) { 
 console.log(i); 
 } 
})(); 
console.log(i); // 抛出错

10.16 私有变量

第11章 期约与异步函数

11.2 期约promise

11.2.1 准备

11.2.1.1 区别实例对象和函数对象
  1. 实例对象通过new创建
function Fn() {
    // body...
}
const fn = new Fn();//Fn是构造函数
//fn 是实例对象


  1. 将函数作为对象
//连接上
console.log(Fn.prototype)

()左边是函数 .的左边是函数对象

11.2.1.2 回调函数
  1. 同步回调函数 理解:立即执行,完全止血了才结束,不会放入回调队列中
let arr=[1,3,5]

arr.forEach(item = >{
    console.log(item)
})
console.log("forEach()之后")

//forEach()括号中的回调函数是同步回调函数,不会放在回调队列,而是立即执行
  1. 异步回调函数 理解:不会立即执行,会放入回调队列中
setTime(function() {console.log("setTimeout()函数")})
console.log("setTimeout()之后")
//setTimeout()之后
//setTimeout()函数
//setTimeout()是异步回调函数,会放在回调队列中
11.2.1.3 js的错误处理err
  1. 常见内置错误
  • ReferenceError 引用错误,引用了不存在的变量

  • TypeError 数据类型不正确错误 类型中没有某个函数或属性 let a; a.xxx();

  • RangeError 超出范围 无限递归

  • SyntaxError 语法错误

  1. 错误处理 捕获错误try。。。cathch。。。
try{
    let a;
    console.log(a.xx);
}catch(error){
    console.log(error.message);
    console.log(error.statck)
}

抛出错误throw error

function something(){
    if (Date.now()%2===1){
        console.log("当前时间为奇数,可以执行任务")
    }else{
        throw new Error("当前时间为偶数,无法执行任务")
    }
}
try{
    something();
}catch(error){
    console.log(error.message)
}
  1. 错误对象 message 错误信息 stack 函数调用栈记录信息

11.2.2 promise的理解和使用

11.2.2.1 promise是什么
11.2.2.1.1 理解
  1. 抽象表达:进行异步编程的新的解决方案
  2. 具体表达:
  • 语法上:构造函数
  • 功能:封装一个异步操作,并获取其结果
11.2.2.1.2 promise的状态改变
  1. pending 变为resolved
  2. pending 变为rejected 以上状态不可逆每个promise只能又一次机会
11.2.2.1.3 基本流程

promise 进行异步操作好状态then坏状态then/

11.2.2.1.4 基本使用
//  创建一个新的promise对象
const promise = new Promise((resolve,reject) =>{//  执行器对象,是一个同步回调 
    //  执行异步操作
    const time = Date.now();
    if(time%2===0){
        //  成功嗲用resolve(value)
        resolve("成功的值:"+time)//括号内传值
    }else{
        //  失败调用reject(reason)
        reject("失败的值:"+time)
    }
})

promise.then(
    value => {//接收得到成功的值value       onResolved
        console.log("成功的回调:",value)
    },
    reason => {//接收失败的值reason       onRejected
        console.log("失败的回调:",reason)
    }
    )

11.2.2.2 为什么使用promse
  1. 指定回调函数的方式更加灵活: 纯回调函数:必须在启动异步人物前指定 promise启动起步任务 =》返回promise对象 +〉 给promise对象绑定回调函数

  2. 支持链式调用,可以解决回调地狱问题 回调地狱:回调函数嵌套, 链式调用:异常传透,多个错误可以卸载一个错误上 终极方法async/await

11.2.2.3 如何使用promise
const promise = new Promise(function(resolve,reject){
    setTime(function() {
        resolve("成功的数据")
        reject("失败的数据")//只能执行一个,
    },1000)
}).then(
    value => {
        console.log("onResolveed()",value)
    }
).catch(
    reason => {
        console.log("onRejected()",reason)
    }
)

11.2.3 自定义promise

11.2.4 async 和 await

第12章 BOM

12.1 window对象

window.innerWidth;
window.innerHeight;//浏览器页面的大小,不包含开发者窗口

window.outerWidth;
window.outerHeight;//浏览器窗口大小

document.documentElement.clientWidth 和 document.documentElement.clientHeight 返回的布局视口的大小

第14章 DOM

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

14.1 节点层级

文档元素html元素是文档的最外层元素

DOM 中总共有 12 种节点类型,这些 类型都继承一种基本类型。

14.1.1 Node类型

DOM Level 1 描述了名为 Node的接口这个接口是所有 DOM 节点类型都必须实现的。

Node接口 在 JavaScript 中被实现为 Node类型在除 IE 之外的所有浏览器中都可以直接访问这个类型。

在 JavaScript 中,所有节点类型都继承 Node类型,因此所有类型都共享相同的基本属性和方法。

  1. nodeName与nodeValue

在使用这两个属性前,最好先检测节点类型

if (someNode.nodeType == 1){ //	检测节点类型
  value = someNode.nodeName; // 会显示元素的标签名
} 

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

  1. 节点关系

每个节点都有一个 childNodes 属性,其中包含一个 NodeList的实例。NodeList是类数组不是Array

访问节点的元素

let firstChild = someNode.childNodes[0]; 
let secondChild = someNode.childNodes.item(1); 
let arrayOfNodes = Array.from(someNode.childNodes); //ES6

parentNode :父元素

previousSibling:上一个节点

nextSibling :下一个节点

firstChild:第一个子节点

lastChild :最后一个子节点

![截屏2021-08-22 上午3.17.45](./截屏2021-08-22 上午3.17.45.png)

hasChildNodes():判断是否有子节点

  1. 操纵节点

appendChild():在列表末尾添加节点,如果传入的是一个存在的节点,该节点会被移动到对象的子节点尾部,一个节点不会同时存在于文档中

insertBefore():插入

// 作为最后一个子节点插入
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild);  // true 
// 作为新的第一个子节点插入
returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode);         // true 
alert(newNode == someNode.firstChild);  // true 
// 插入最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild); 
alert(newNode == someNode.childNodes[someNode.childNodes.length - 2]); // true

replaceChild():节点替换

let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

**removeChild()**删除节点

// 删除第一个子节点
let formerFirstChild = someNode.removeChild(someNode.firstChild); // 删除最后一个子节点
let formerLastChild = someNode.removeChild(someNode.lastChild); 
  1. 其他方法

cloneNode():复制节点

let deepList = myList.cloneNode(true);  //深复制,复制节点和子节点数
alert(deepList.childNodes.length);    // 3IE9之前的版本或7其他浏览器 let shallowList = myList.cloneNode(false); 孤儿节点,没有子节点和父节点
alert(shallowList.childNodes.length); // 0 

14.1.2 Document类型

document 是HTMLDocument的实例HTMLDocument继承 Document表示整个 HTML 页面。

document是 window 3 对象的属性,因此是一个全局对象。

document对象可用于获取关于页面的信息以及操纵其外观和底层结构

  1. 文档子节点

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

let html = document.documentElement;     // 取得对<html>的引用
alert(html === document.childNodes[0]);  // true                                       11 alert(html === document.firstChild);     // true 

body获取body

let body = document.body; // 取得对<body>的引用

doctype<!doctype>标签

  1. 文档信息

title:读写页面的标题,修改 title 属性并不会改变