2.1.2 引用数据类型(对象类型)
- JSON(Object)
- 数组(Array) 可变
- 函数(Function)
- 正则(RegExp)
- 日期(Date)
第一章、异常处理机制
1.1 异常概述
在ES3之前JavaScript代码执行的过程中,一旦出现错误,整个JavaScript代码都会停止执行,这样就显的代码非常的不健壮。
在Java或C#等一些高级语言中,都提供了异常处理机制,可以处理出现的异常,而不会停止整个应用程序。
从ES3开始,JavaScript也提供了类似的异常处理机制,从而让JavaScript代码变的更健壮,即使执行的过程中出现了异常,也可以让程序具有了一部分的异常恢复能力。
当错误发生时,JavaScript 提供了错误信息的内置 error 对象。
error 对象提供两个有用的属性:name 和 message 。
Error 对象属性
Error Name Values
error 的 name 属性可返回六个不同的值:
1.2 异常捕捉
ES3开始引入了 try-catch 语句,是 JavaScript 中处理异常的标准方式。
语法格式:
try {
// 可能发生异常的代码
} catch (error) {
// 发生错误执行的代码
} finally {
// 无论是否出错都会执行的代码
}
在 try…catch 中,try 中一旦出现错误则try中的其它语句不能执行,执行catch中的语句,如果不出现错误则 catch 中的语句不会执行。
Javascript 参考其它编程语言,也提供了一种 finally 语句:不管 try 中的语句有没有错误,在最后都会执行 finally 中的语句。也就是说,try 中语句不发生错误执行完毕后会执行 finally 中的语句,try 中的语句发生错误,则执行 catch中的语句,catch 中的语句执行完毕后也会执行 finally 中的语句。
try {
console.log(a);
console.log("a未定义肯定报错,你看不见我");
} catch (error) {
// 发生错误执行的代码
console.log(error);
} finally {
// 无论是否出错都会执行的代码
console.log("finally 执行了 ...")
}
总结:一般都带着catch语句,即为try...catch组合
1.3 异常演示
1.3.1 Eval 错误
EvalError 指示 eval() 函数中的错误。更新版本的 JavaScript 不会抛出任何 EvalError,请使用 SyntaxError 代替。
案例演示:
try {
eval("alert('Hello)"); // 缺少 ' 会产生错误
} catch (error) {
console.log(error)
}
1.3. 2 范围错误
RangeError 会在您使用了合法值的范围之外的数字时抛出。
案例演示:您不能将数字的有效位数设置为 500。
var num = 1;
try {
num.toPrecision(500); // 数无法拥有 500 个有效数
} catch (error) {
console.log(error)
}
1.3.3 引用错误
假如您使用(引用)了尚未声明的变量,则 ReferenceError 会被抛出:
案例演示:
var x;
try {
x = y + 1; // y 无法被引用(使用)
} catch (error) {
console.log(error)
}
1.3.4 语法错误
假如您计算带语法错误的代码,会 SyntaxError 被抛出:
案例演示:
try {
eval("alert('Hello)"); // 缺少 ' 会产生错误
} catch (error) {
console.log(error)
}
1.3.5 类型错误
假如您使用的值不在期望值的范围之内,则 TypeError 被抛出:
案例演示:
var num = 1;
try {
num.toUpperCase(); // 您无法将数字转换为大写
} catch (error) {
console.log(error)
}
1.3.6 URI 错误
假如您在 URI 函数中使用非法字符,则 URIError 被抛出:
案例演示:
try {
decodeURI("%%%"); // 您无法对这些百分号进行 URI 编码
} catch (error) {
console.log(error)
}
1.4 异常抛出
在大部分的代码执行过程中,都是出现错误的时候,由浏览器(javascript引擎)抛出异常,然后程序或者停止执行或被try…catch 捕获。
然而有时候我们在检测到一些不合理的情况发生的时候也可以主动抛出错误,请使用 throw 关键字抛出来主动抛出异常。
注意事项:
- thow后面就是我们要抛出的异常对象,在以前的时候都是出现错误的时候浏览器抛出异常对象,只是现在是我们自己主动抛出的异常对象。
- 只要有异常对象抛出,不管是浏览器抛出的,还是代码主动抛出,都会让程序停止执行。如果想让程序继续执行,则有也可以用try…catch来捕获。
- 每一个错误类型都可以传入一个参数,表示实际的错误信息。
- 我们可以在适当的时候抛出任何我们想抛出的异常类型。
- throw new SyntaxError("语法错误...");
1.4.1 主动抛出内置异常
/*该函数接收一个数字,返回它的平方。*/
function foo(num) {
if (typeof num == "number") {
return num * num;
} else {
throw new TypeError("您输入的是一个非法数字!")
}
}
console.log(foo(4));
console.log(foo("abc"));
1.4.2 主动抛出自定义异常
我们不仅仅可以抛出js内置的错误类型的对象,也可以自定义错误类型,然后抛出自定义错误类型的对象。
如果要自定义错误类型,只需要继承任何一个自定义错误类型都可以,一般直接继承Error即可。
/*自定义错误*/
function MyError(message) {
this.message = message
this.name = "自定义错误";
}
MyError.prototype = new Error();
try {
throw new MyError("注意:这是自定义错误类型asf");
} catch (error) {
console.log(error.message);
}
第二章、JSON
一、JSON概述
JSON的基本使用(详解)_JAVA成神的博客-CSDN博客
JSON:JavaScript Object Notation(JavaScript 对象标记法),它是一种存储和交换数据的语法。是一种轻量级的数据交换格式,它是一种用于存储和交换数据的语言无关、文本格式的数据表示形式。
当数据在浏览器与服务器之间进行交换时,这些数据只能是文本,JSON 属于文本并且我们能够把任何 JavaScript 对象转换为 JSON,然后将 JSON 发送到服务器。我们也能把从服务器接收到的任何 JSON 转换为 JavaScript 对象。以这样的方式,我们能够把数据作为 JavaScript 对象来处理,无需复杂的解析和转译。
JSON对象就是JS对象,JSON的本质在内存中是字符串,只是外在像JS对象一样,可以使用JS对象的访问方法访问其中元素
JSON之所以受欢迎,主要是因为它仍然使用 JavaScript 语法来描述数据对象,并没有改变开发人员的使用习惯,这更容易被开发人员接受。由于这种相似性,JavaScript 程序就无需解析器,便可以直接用 JSON 数据来生成原生的 JavaScript 对象
- 在定义JSON键/值时,先是键名,后面写一个冒号,然后是值。如:
- "github": "https://github.com/leiqikui"
- 这就等价于这条 JavaScript 语句:
- github = "https://github.com/leiqikui"
二、JSON语法
在json中,每一个数据项,都是由一个键值对(或者说是名值对)组成的,但是键必须是字符串,且由双引号包围,而值必须是以下数据类型之一:
- 字符串(在 JSON 中,字符串值必须由双引号编写)
- 数字
- 对象(JSON 对象)
- 数组
- 布尔
- null
JSON 的值不可以是以下数据类型之一:
- 函数
- 日期
- undefined
因为 JSON 语法由 JavaScript 对象标记法衍生而来,所以很少需要其它额外的软件来处理 JavaScript 中的 JSON。
三、JSON数据类型
统称为JSON对象
2.3.1 JSON 字符串
JSON 中的字符串必须用双引号包围。
{"name": "John"}
2.3.2 JSON 数字
JSON 中的数字必须是整数或浮点数。
{"age": 30}
2.3.3 JSON 对象(狭义)
JSON 中的值可以是对象,JSON 中作为值的对象必须遵守与 JSON 对象相同的规则。
{
"employee": {"name": "Bill Gates", "age": 62, "city": "Seattle"}
}
2.3.4 JSON 数组
JSON 中的值可以是数组。
{
"employees": ["Bill", "Steve", "David"]
}
2.3.5 JSON 布尔
JSON 中的值可以是 true/false。
{"sale": true}
2.3.6 JSON null
JSON 中的值可以是 null。
{"middlename": null}
2.4 JSON字符串转JS对象
JSON.parse():可以将以JSON字符串转换为JS对象,它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
var jsonStr = '{"name":"孙悟空","age":18,"gender":"男"}';
var obj = JSON.parse(jsonStr);
console.log(obj);
2.5 JS对象转JSON字符串 JSON.stringify()
JSON.stringify()
是一个将 JavaScript 对象转换为 JSON 字符串的方法。该方法接受三个参数:
- 要序列化的 JavaScript 对象、
- 一个可选的替换函数、
- 一个可选的空格数值。
语法如下:
JSON.stringify(value[, replacer [, space]])
其中,value
是要序列化的 JavaScript 对象;replacer
是一个函数,用于转换生成的 JSON 对象中的值,或者如果指定数组,则仅包括具有指定键名的属性。space
是一个数值,用于控制缩进的空格数。
举个例子,假设我们有一个 JavaScript 对象:
const myObject = {
name: "John",
age: 30,
hobbies: ["reading", "running", "swimming"],
address: {
street: "123 Main St",
city: "New York",
state: "NY",
zip: "10001"
}
};
要将这个对象序列化为 JSON 字符串,可以这样使用 JSON.stringify()
:
const jsonString = JSON.stringify(myObject);
console.log(jsonString);
这将输出以下字符串:
{
"name": "John",
"age": 30,
"hobbies": ["reading","running","swimming"],
"address": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zip": "10001"
}
}
可以看到,每个属性都转换为一个字符串键值对,属性值可以是字符串、数字、布尔值、数组、对象或 null。
可以在第二个参数 replacer
中传入一个转换函数,对 JSON 对象进行定制化转换,或者只选择包含某些属性,排除某些属性。
例如,我们想排除 address
属性,可以这样使用:
const jsonString = JSON.stringify(myObject, (key, value) => {
if (key === 'address') {
return undefined;
}
return value;
});
console.log(jsonString);
这将输出以下字符串:
{
"name": "John",
"age": 30,
"hobbies": ["reading","running","swimming"]
}
在第三个参数 space
中,可以传入一个整数或字符串,控制 JSON 字符串的缩进格式。例如:
const jsonString = JSON.stringify(myObject, null, 2);
console.log(jsonString);
这将输出以下字符串:
{
"name": "John",
"age": 30,
"hobbies": [
"reading",
"running",
"swimming"
],
"address": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zip": "10001"
}
}
可以看到,使用了 2
空格作为缩进。如果使用字符串作为 space
参数,例如 "\t"
,则使用制表符进行缩进。
JSON.stringify():可以将一个JS对象转换为JSON字符串,需要一个js对象作为参数,会返回一个JSON字符串
var obj = {name: "猪八戒", age: 28, gender: "男"};
var jsonStr = JSON.stringify(obj);
console.log(jsonStr);
3、闭包机制Closure
JavaScript中的闭包_javascript 闭包_Encounter∞的博客-CSDN博客
3.1 闭包概念
- 一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。
- 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。
- 在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
- 闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境,相当于一个符号查找表。
- 闭包跟函数最大的区别在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行。
3.2 闭包作用
- 它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中
3.3 闭包演示
function fun1() {
var a = 2;
function subFun() {
a++;
console.log(a);
}
return subFun;
}
var f1 = fun1();
f1();
f1();
console.log("===============");
function fun2() {
var a = 2;
function subFun() {
a--;
console.log(a);
}
return subFun;
}
var f2 = fun2();
f2();
f2();
console.log("===============");
3.4 闭包生命周期
生命周期:
- 产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
- 死亡:在嵌套的内部函数成为垃圾对象时就死亡了
演示说明:
function fn1() {
//此时闭包就已经产生了(函数提升, 内部函数对象已经创建了)
var a = 2;
function fn2() {
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f(); // 3
f(); // 4
f = null; //闭包死亡(包含闭包的函数对象成为垃圾对象)
3.5 闭包应用
闭包应用: 定义JS模块
- 具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 只向外暴露一个包含n个方法的对象或函数
- 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
案例演示:
第一种格式:myModule.js (直接在js里面用node执行)
function myModule() {
//私有数据
var msg = 'Hello, World';
//操作数据的函数
function doSomething() {
console.log('doSomething() ' + msg.toUpperCase());
}
function doOtherthing() {
console.log('doOtherthing() ' + msg.toLowerCase());
}
//向外暴露对象(给外部使用的方法)
return {
doSomething: doSomething,
doOtherthing: doOtherthing
}
}
var module = myModule();
module.doSomething();
module.doOtherthing();
第二种格式:myModule.js
(function (window) {
//私有数据
var msg = 'Hello, World';
//操作数据的函数
function doSomething() {
console.log('doSomething() ' + msg.toUpperCase());
}
function doOtherthing() {
console.log('doOtherthing() ' + msg.toLowerCase());
}
//向外暴露对象(给外部使用的方法)
window.myModule = {
doSomething: doSomething,
doOtherthing: doOtherthing
}
})(window);
myModule.doSomething();
myModule.doOtherthing();
第二种使用:index.html
4、AJAX
4.1 AJAX概述
传统的web交互是用户触发一个http请求服务器,然后服务器收到之后,在做出响应到用户,并且返回一个新的页面,每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。这个做法浪费了许多带宽,由于每次应用的交互都需要向服务器发送请求,应用的响应时间就依赖于服务器的响应时间,这导致了用户界面的响应比本地应用慢得多。
AJAX 的出现,刚好解决了传统方法的缺陷,AJAX 是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新,这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
4.2 AJAX的XMLHttpRequest对象
AJAX 的核心是 XMLHttpRequest 对象。 所有现代浏览器都支持 XMLHttpRequest 对象。
XMLHttpRequest 对象用于幕后同服务器交换数据,这意味着可以更新网页的部分,而不需要重新加载整个页面。
所有现代浏览器(Chrom、IE7+、Firefox、Safari 以及 Opera)都有内建的XMLHttpRequest 对象。
创建 XMLHttpRequest 的语法是:
variable = new XMLHttpRequest();
老版本的 Internet Explorer(IE5 和 IE6)使用 ActiveX 对象:
variable = new ActiveXObject("Microsoft.XMLHTTP");
为了应对所有浏览器,包括 IE5 和 IE6,请检查浏览器是否支持 XMLHttpRequest 对象。如果支持,创建 XMLHttpRequest 对象,如果不支持,则创建 ActiveX 对象:
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
但是需要注意的是,出于安全原因,现代浏览器不允许跨域访问,这意味着尝试加载的网页和 XML 文件都必须位于相同服务器上。
4.3 AJAX的XMLHttpRequest对象方法
4.4 AJAX的XMLHttpRequest对象属性
4.4 AJAX的GET请求
工程结构:
users.json
[
{"name":"孙悟空","age":18,"gender":"男"},
{"name":"猪八戒","age":19,"gender":"男"},
{"name":"唐僧","age":20,"gender":"男"},
{"name":"沙和尚","age":21,"gender":"男"}
]
index.html
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url
ajax.open("get", "users.json");
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五:如果能够进到这个判断,说明数据完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入响应的内容
}
};
控制台
4.5 AJAX的POST请求
工程结构:
users.json
[
{"name":"孙悟空","age":18,"gender":"男"},
{"name":"猪八戒","age":19,"gender":"男"},
{"name":"唐僧","age":20,"gender":"男"},
{"name":"沙和尚","age":21,"gender":"男"}
]
index.html
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的类型及url,注意:post请求一定要添加请求头才行不然会报错
ajax.open("post", "users.json");
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
//步骤五:如果能够进到这个判断,说明数据完美的回来了,并且请求的页面是存在的
if (ajax.readyState == 4 && ajax.status == 200) {
console.log(ajax.responseText);//输入响应的内容
}
};
控制台:
5、迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费。
- 迭代是访问集合元素的一种方式。
- 可迭代是说一个对象可以用迭代的方式访问其内容。
- 迭代器是一个可以记住遍历的位置的对象。
原生具备 iterator 接口的数据:
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
注意:需要自定义遍历数据的时候,要想到迭代器
5.1 可迭代协议
实现 Iterator 接口(可迭代协议)要求同时具备支持迭代的自我识别能力和和创建实现 Iterator 接口的对象的能力。在 ECMAScript 中,这意味着必须暴露一个 Symbol.iterator 属性作为“默认迭代器”。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。
很多内置类型都实现了 Iterator 接口。包括字符串、数组、Map、Set、arguments 对象。
arr[Symbol.iterator] 理解成arr对象访问其Symbol.itetator 可迭代属性
// 没有实现迭代器工厂函数的类型
const num = 1;
const obj = {};
console.log(num[Symbol.iterator]); // undefined
console.log(obj[Symbol.iterator]); // undefined
// 实现了迭代器工厂函数的类型
const arr = [1, 2, 3];
const set = new Set([1, 2, 3]);
console.log(arr[Symbol.iterator]); // [Function: values]
console.log(set[Symbol.iterator]); // [Function: values]
调用迭代器工厂函数会返回一个迭代器。
console.log(arr[Symbol.iterator]()); // Object [Array Iterator] {}
console.log(set[Symbol.iterator]()); // [Set Iterator] { 1, 2, 3 }
实际写代码过程中,不需要显式调用这个工厂函数来生成迭代器。实现可迭代协议的所有类型都会自动兼容接收可迭代对象的任何语言特性。接收可迭代对象的原生语言特性包括:for-of 循环、数组解构、扩展操作符、Array.from()、创建集合、创建映射等等。
这些原生的语言结构会在后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器。
const arr = [1, 2, 3];
// for-of 循环
for (const item of arr) {
console.log(item); // 1 2 3
}
// 数组解构
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3
// 扩展操作符
let arr2 = [...arr];
// 使用 Array.from() 赋值数组
let arr3 = Array.from(arr);
// 创建集合
let set = new Set(arr);
// 创建映射
let map = new Map(arr.map((x, i) => [i, x]))
console.log(map); // Map(3) { 0 => 1, 1 => 2, 2 => 3 }
工作原理:
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
案例演示:遍历数组
//声明一个数组
const xiyou = ["唐僧", "孙悟空", "猪八戒", "沙僧"];
//使用 for...of 遍历数组
for (let v of xiyou) {
console.log(v);
}
console.log("===============");
//获取迭代器对象
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
案例演示:自定义遍历数据
//声明一个对象
const banji = {
name: "五班",
stus: [
"张三",
"李四",
"王五",
"小六"
],
[Symbol.iterator]() {
//索引变量
let index = 0;
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = {value: _this.stus[index], done: false};
//下标自增
index++;
//返回结果
return result;
} else {
return {value: undefined, done: true};
}
}
};
}
}
//遍历这个对象
for (let v of banji) {
console.log(v);
}
6、生成器
yield和return的区别-- 超详细_yield return_不良使的博客-CSDN博客
【JavaScript】18.迭代器和生成器_js迭代器和生成器_Tourry的博客-CSDN博客
生成器可以在代码块中暂停和恢复代码。使用生成器可以自定义迭代器。
6.1 生成器基础
在函数名称前面或者 function 关键字后面加一个星号*
表示它是一个生成器。只要是可以定义函数的地方,都可以定义生成器。
function* generatorFn() {}
let generatorFn = function* () {};
let obj = {
*generatorFn() {},
};
注意:箭头函数不能用来定义生成器函数。
调用生成器函数会产生一个生成器对象。生成器对象一开始位于**暂停执行(suspended)**的状态。生成器对象实现了 Iterator 接口,因此有 next() 方法。调用这个方法可以让生成器开始或者恢复执行。next() 方法的返回值类似于迭代器,有一个 done 属性和一个 value 属性。
function* generatorFn() {}
const g = generatorFn();
console.log(g.next()); // { value: undefined, done: true }
value 属性的返回值可以通过生成器函数的返回值指定,默认返回值是 undefined。只有在调用 next() 方法后,生成器函数才会开始执行。
function* generatorFn() {
return "foo";
}
const g = generatorFn(); // 此时不执行函数体,只有调用next() 后才执行函数体
console.log(g.next()); // { value: 'foo', done: true }
生成器对象实现了 Iterable 接口,默认迭代器即自身。
function* generatorFn() {}
const g = generatorFn();
console.log(g[Symbol.iterator]() === g);
6.2 通过 yield 中断执行
只能使用next()方法,访问return的值
yield 关键字可以让生成器停止和开始执行。生成器函数在遇到 yield 关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域会被保留。停止执行的生成器函数只能通过在生成器对象上调用 next() 方法来恢复执行。
function* generatorFn() {
yield "foo";
return "bar";
}
const g = generatorFn();
console.log(g.next()); // { value: 'foo', done: false }
console.log(g.next()); // { value: 'bar', done: true }
注意:
- 生成器函数会针对每个生成器对象区分作用域。在一个生成器对象上调用 next() 不影响其它生成器对象。
- yield 关键字只能在生成器内部使用,用在其它地方会抛出错误。
- yield 关键字必须直接定义在生成器函数内部定义中,出现在嵌套的非生成器函数中会抛出错误。
6.2.1 生成器对象作为可迭代对象
function* generatorFn() {
yield 1;
yield 2;
yield 3;
}
for (const x of generatorFn()) {
console.log(x); // 1 2 3
}
6.2.2 使用 yield 实现输入输出
除了可以作为函数的中间返回语句使用,yeild 关键字还可以作为函数中间参数使用。上一次让生成器函数暂停的yeild 关键字会接收到传给 next() 方法的第一个值。第一次调用 next() 传入的值不会被使用,因为这一次调用是为了开始执行生成器函数。
function* generatorFn() {
console.log(yield);
console.log(yield);
}
let g = generatorFn();
g.next("bar"); // 没有任何输出,因为这次是为了开始执行生成器函数
g.next("baz"); // baz
g.next("qux"); // qux
ield 关键字可以同时用于输入和输出。
function* generatorFn() {
return yield "foo";
}
const g = generatorFn();
console.log(g.next()); // foo
console.log(g.next("bar")); // bar
6.2.3 使用 yield* 产生可迭代对象
使用型号*
可以增强 yield 的行为,让它能够迭代一个可迭代对象,从而一次产出一个值。
function* generatorFn() {
yield* [1, 2, 3];
}
const g = generatorFn();
for (const item of g) {
console.log(item); // 1 2 3
}
6.3 生成器作为默认迭代器
因为生成器对象实现了 Iterable 接口,而且生成器函数和默认迭代器工厂函数被调用之后都产生迭代器。因此,生成器适合作为默认的迭代器工厂函数。
class Foo {
constructor() {
this.values = [1, 2, 3];
}
*[Symbol.iterator]() {
yield* this.values;
}
}
const f = new Foo();
for (const x of f) {
console.log(x); // 1 2 3
}
7、遍历对象的七中方法
1、for...in
对普通对象遍历可枚举属性,获取键名
for (let xx in obj) :i代表key
var obj = {
a: 1,
b: 2
}
Object.defineProperty(obj,'a',{
//a属性是不可枚举的,所以不会遍历
enumerable: false
})
for(let key in obj){
console.log(key);
}
如果用for...of遍历普通对象(不可迭代对象)会报错
2、for...of
对可迭代对象循环迭代,获取键值
for (let xx of obj) :i代表value
可迭代对象必须实现Iterator方法,并在其内部不断调用next方法,常见的可迭代对象有
- Array
- Arguments
- Set
- Map
- String
-
let str1 = '123'; for(let i of str1){ console.log(i); }
-
- TypedArray
- NodeList
for(let x of arr){
console.log(x);
}
console.log('=============================');
for(let x in arr){
console.log(x);
}
可迭代对象的键就是其索引号
3、Object.keys()
返回包含key的数组
4、Object.values()
返回包含value的数组
5、Object.getOwnPropertyNames()
返回包含key的数组
上述的所有方法都是遍历不到symbol类型的(注意,是遍历时取不到symbol,并不是说我们访问不到对象的symbol类型)
6、Object.getOwnPropertySymbols()
返回对象中只包含symbol类型key的数组
7、Reflect.ownKeys()
返回对象中所有类型key的数组(包含symbol)
8、class 类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是 一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,它的一些如下:
- class:声明类
- constructor:定义构造函数初始化
- extends:继承父类
- super:调用父级构造方法
- static:定义静态方法和属性 静态方法只能由类调用
//父类
class Phone {
//构造方法
constructor(brand, color, price) {
this.brand = brand;
this.color = color;
this.price = price;
}
//对象方法
call() {
console.log("我可以打电话!!!")
}
}
//子类
class SmartPhone extends Phone {
constructor(brand, color, price, screen, pixel) {
super(brand, color, price);
this.screen = screen;
this.pixel = pixel;
}
//子类方法
photo() {
console.log("我可以拍照!!");
}
playGame() {
console.log("我可以玩游戏!!");
}
//方法重写
call() {
console.log("我可以进行视频通话!!");
}
//静态方法
static run() {
console.log("我可以运行程序")
}
static connect() {
console.log("我可以建立连接")
}
}
//实例化对象
const Nokia = new Phone("诺基亚", "灰色", 230);
const iPhone6s = new SmartPhone("苹果", "白色", 6088, "4.7inch", "500w");
console.log('=====开始调用父类方法=====');
//调用父类方法
Nokia.call();
console.log('=====开始调用子类方法=====');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();
// iPhone6s.run(); //静态方法只能由类调用
class 私有属性
私有属性只能在class中访问
class Person {
//公有属性
name;
//私有属性
#age;
#weight;
//构造方法
constructor(name, age, weight) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
//普通方法
intro() {
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
//实例化
const girl = new Person("小可爱", 18, "45kg");
girl.intro();
9、浅拷贝和深拷贝
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝;如果B没变,那就是深拷贝,深拷贝与浅拷贝的概念只存在于引用数据类型。
9.1 浅拷贝
var obj1 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = obj1;
// 当修改obj2的属性和方法的时候,obj1相应的属性和方法也会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);
9.2 深拷贝
Array:slice()、concat()、Array.from()、… 操作符:只能实现一维数组的深拷贝
slice()方法演示:
var arr1 = [1, 2, 3, [1,2]];
var arr2 = arr1; //浅拷贝
var arr3 = arr1.slice(); //深拷贝
arr1.push(5);
arr1[0] = 200;
arr1[3][0]=100;
console.log(arr1);
console.log(arr2);
console.log(arr3);
concat()方法演示:
var arr1 = [1, 2, 3, 4];
var arr2 = arr1.concat();
arr2[0] = 200;
console.log(arr1);
console.log(arr2);
Array.from()方法演示:
var arr1 = [1, 2, 3, 4];
var arr2 = Array.from(arr1);
arr2[0] = 200;
console.log(arr1);
console.log(arr2);
… 操作符演示:
var arr1 = [1, 2, 3, 4];
var arr2 = [...arr1];
arr2[0] = 200;
console.log(arr1);
console.log(arr2);
Object:Object.assign()、… 操作符:只能实现一维对象的深拷贝
Object.assign()方法演示:
var obj1 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = Object.assign({}, obj1);
// 当修改obj2的属性和方法的时候,obj1相应的属性和方法不会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);
… 操作符演示:
var obj1 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = {
...obj1
};
// 当修改obj2的属性和方法的时候,obj1相应的属性和方法不会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);
JSON.parse(JSON.stringify(obj)):可实现多维对象的深拷贝,但会忽略 undefined
、 任意的函数
、Symbol 值
var obj1 = {
name: "张三",
age: 20,
birthday: {
year: 1997,
month: 12,
day: 5
},
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = JSON.parse(JSON.stringify(obj1));
// 当修改obj2的属性和方法的时候,obj1相应的属性和方法不会改变
obj2.name = "李四";
obj2.birthday.year = 1996;
console.log(obj1);
console.log(obj2);
注意:进行JSON.stringify()序列化的过程中,undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时),由上面可知,JS 提供的自有方法并不能彻底解决Array、Object的深拷贝问题,因此我们应该自己实现。
多维对象的深拷贝(通用版)
var obj1 = {
name: "张三",
age: 20,
birthday: {
year: 1997,
month: 12,
day: 5
},
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = deepClone(obj1);
// 当修改obj2的属性和方法的时候,obj1相应的属性和方法不会改变
obj2.name = "李四";
obj2.birthday.year = 1996;
console.log(obj1);
console.log(obj2);
/**
* 深拷贝通用方法
* @param obj 需要拷贝的对象
* @param has
* @returns {any|RegExp|Date}
*/
/*
obj是需要被复制的对象。
has是一个 WeakMap 对象,用来存储已经被复制的对象,防止出现自引用导致的死循环。默认为一个新的 WeakMap 对象。
首先进行类型检查,如果 obj 是 null 或者基本类型,则直接返回 obj。如果 obj 是 Date 或 RegExp 类型,则返回 obj。
newObj 是一个新的对象,和 obj 具有相同的类型和构造函数。
如果 obj 已经被复制过了,直接返回它的副本 newObj,防止死循环。
将 obj 和 newObj 存入 has 中,表示已经复制过了。
使用 for...in 循环遍历 obj 的属性及方法,如果该属性是 obj 自身的属性,那么就将该属性复制到 newObj 中,通过递归调用 deepClone 处理属性值。
最后返回 newObj。
总之,这段代码实现了一个通用的深拷贝函数,可以用于复制对象,包括属性和方法,并且防止出现自引用导致的死循环。
*/
function deepClone(obj, has = new WeakMap()) {
// 类型检查
if (obj == null) return obj;
if (obj instanceof Date) return obj;
if (obj instanceof RegExp) return obj;
if (!(typeof obj == "object")) return obj;
// 构造对象
const newObj = new obj.constructor;
// 防止自引用导致的死循环
if (has.get(obj)) return has.get(obj);
has.set(obj, newObj);
// 循环遍历属性及方法
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
// 返回对象
return newObj;
}
10、async 函数
10.1 async 函数的语法:
async function fn(){
}
async 函数的返回值:
- 返回的结果不是一个 Promise 类型的对象,返回的结果就是成功 Promise 对象
- 返回的结果如果是一个 Promise 对象,具体需要看执行resolve方法还是reject方法
- 抛出错误,返回的结果是一个失败的 Promise
async 函数的演示
//async 函数
async function fn() {
return new Promise((resolve, reject) => {
resolve('成功的数据');
// reject("失败的错误");
});
}
const result = fn();
//调用 then 方法
result.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
});
10.2 await 表达式
async 和 await 两种语法结合可以让异步代码像同步代码一样
await 表达式的注意事项:
- await 必须写在 async 函数中
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
await 表达式的语法演示:
//创建 promise 对象
const p = new Promise((resolve, reject) => {
resolve("用户数据");
//reject("失败啦!");
})
//await 要放在 async 函数中.
async function fun() {
try {
let result = await p;
console.log(result);
} catch (e) {
console.log(e);
}
}
//调用函数
fun();
await 表达式的案例演示:async与await封装AJAX请求
// 发送 AJAX 请求, 返回的结果是 Promise 对象
function sendAJAX(url) {
return new Promise((resolve, reject) => {
//1. 创建对象
const x = new XMLHttpRequest();
//2. 初始化
x.open('GET', url);
//3. 发送
x.send();
//4. 事件绑定
x.onreadystatechange = function () {
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
resolve(x.response);//成功
} else {
reject(x.status);//失败
}
}
}
})
}
// async 与 await 测试
async function fun() {
//发送 AJAX 请求 1
let joke = await sendAJAX("https://api.apiopen.top/getJoke");
//发送 AJAX 请求 2
let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')
console.log(joke);
console.error(tianqi);//为了区别数据,我这里用红色的error输出
}
// 调用函数
fun();
11、
六、JavaScript DOM
1、DOM概述
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
HTML DOM 模型被结构化为 对象树 :
通过这个对象模型,JavaScript 获得创建动态 HTML 的所有力量:
- JavaScript 能改变页面中的所有 HTML 元素
- JavaScript 能改变页面中的所有 HTML 属性
- JavaScript 能改变页面中的所有 CSS 样式
- JavaScript 能删除已有的 HTML 元素和属性
- JavaScript 能添加新的 HTML 元素和属性
- JavaScript 能对页面中所有已有的 HTML 事件作出反应
- JavaScript 能在页面中创建新的 HTML 事件
换言之:HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。
2、DOM文档节点
2.1 节点概述
节点(Node),是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点。
- 比如:html标签、属性、文本、注释、整个文档等都是一个节点。
虽然都是节点,但是实际上它们的具体类型是不同的。
比如:标签我们称为元素节点、属性称为属性节点、文本称为 文本节点、文档称为文档节点。
节点的类型不同,属性和方法也都不尽相同。
节点:Node——构成HTML文档最基本的单元。
常用节点分为四类:
- 文档节点:整个HTML文档
- 元素节点:HTML文档中的HTML标签
- 属性节点:元素的属性
- 文本节点:HTML标签中的文本内容
2.2 节点属性
2.3 文档节点
文档节点(Document)代表的是整个HTML文 档,网页中的所有节点都是它的子节点。
document对象作为window对象的属性存在的,我们不用获取可以直接使用。
通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
2.4 元素节点
HTML中的各种标签都是元素节点(Element),这也是我们最常用的一个节点。
浏览器会将页面中所有的标签都转换为一个元素节点, 我们可以通过document的方法来获取元素节点。
例如:document.getElementById(),根据id属性值获取一个元素节点对象。
2.5 属性节点
属性节点(Attribute)表示的是标签中的一个一个的属 性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。可以通过元素节点来获取指定的属性节点。
例如:元素节点.getAttributeNode("属性名"),根据元素节点的属性名获取一个属性节点对象。
注意:我们一般不使用属性节点。
2.6 文本节点
文本节点(Text)表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点,它包括可以字面解释的纯文本内容。文本节点一般是作为元素节点的子节点存在的。获取文本节点时,一般先要获取元素节点,在通过元素节点获取文本节点。
例如:元素节点.firstChild;,获取元素节点的第一个子节点,一般为文本节点。
3、DOM文档操作
文档对象代表您的网页,,如果您希望访问 HTML 页面中的任何元素,那么您总是从访问 document 对象开始。
下面是一些如何使用 document 对象来访问和操作 HTML 的实例。
3.1 查找 HTML 元素
3.1.1 方法介绍
3.1.2 方法演示
需求描述:创建一个按钮,通过id获取按钮节点对象
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementById("btn");
console.log(btn);
</script>
</body>
</html>
需求描述:创建一个按钮,通过标签名获取按钮节点对象数组
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button>我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementsByTagName("button");
console.log(btn);
</script>
</body>
</html>
需求描述:创建一个按钮,通过类名获取按钮节点对象数组
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button class="btn">我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementsByClassName("btn");
console.log(btn);
</script>
</body>
</html>
需求描述:创建一个按钮,通过CSS选择器选择该按钮
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button class="btn">我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.querySelector(".btn");
console.log(btn);
</script>
</body>
</html>
需求描述:创建一个无序列表,通过CSS选择器选择该列表的所有li
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul class="list">
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
<li>列表项4</li>
</ul>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var list = document.querySelectorAll(".list li");
console.log(list);
</script>
</body>
</html>
3.2 获取 HTML 的值
3.2.1 方法介绍
3.2.2 方法演示
需求描述:创建一个按钮,然后获取按钮的文本内容
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementById("btn");
console.log(btn.innerText);
</script>
</body>
</html>
需求描述:创建一个div,然后在div中插入一个h1标题,获取div中的html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box">
<h1>我是Box中的大标题</h1>
</div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
console.log(box.innerHTML);
</script>
</body>
</html>
需求描述:创建一个超链接,默认为空,设置href属性为https://www.baidu.com
,使用JavaScript代码读取href属性
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a id="a" href="https://www.baidu.com">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
console.log(a.href);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a id="a" href="https://www.baidu.com">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
console.log(a.getAttribute("href"));
</script>
</body>
</html>
需求描述:创建一个正方形div,默认颜色为红色,使用JavaScript代码获取div的宽度
注意:如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color,需要将这种样式名修改为驼峰命名法,去掉-,然后将-后的字母大写,我们通过style属性设置的样式都是行内样式,同样的获取也是行内样式,而行内样式有较高的优先级,所以通过JS修改的样式往往会立即显示,但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加!important
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div style="width: 100px;height: 100px;background: red;" id="box"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
console.log(box.style.width);
</script>
</body>
</html>
3.3 改变 HTML 的值
3.3.1 方法介绍
3.3.2 方法演示
需求描述:创建一个按钮,然后改变按钮的文本内容
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">我是按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementById("btn");
btn.innerText = "我是JavaScript的按钮";
console.log(btn);
</script>
</body>
</html>
需求描述:创建一个div,然后在div中插入一个h1标题
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
box.innerHTML = "<h1>我是Box中的大标题</h1>";
console.log(box);
</script>
</body>
</html>
**需求描述:创建一个超链接,默认为空,使用JavaScript代码设置href属性为https://www.baidu.com
**
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a id="a" href="">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
a.href="https://www.baidu.com";
console.log(a);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a id="a" href="">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
a.setAttribute("href", "https://www.baidu.com");
console.log(a);
</script>
</body>
</html>
需求描述:创建一个正方形div,默认颜色为红色,使用JavaScript代码改变为绿色
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div style="width: 100px;height: 100px;background: red;" id="box"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
box.style.background = "green";
console.log(box);
</script>
</body>
</html>
3.4 修改 HTML 元素
3.4.1 方法介绍
3.4.2 方法演示
案例演示1:创建一个ul列表,然后在该列表中追加4个li标签
第一种方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var ul = document.createElement("ul");
var li1 = document.createElement("li");
var text1 = document.createTextNode("列表项1");
li1.appendChild(text1);
ul.appendChild(li1);
var li2 = document.createElement("li");
var text2 = document.createTextNode("列表项2");
li2.appendChild(text2);
ul.appendChild(li2);
var li3 = document.createElement("li");
var text3 = document.createTextNode("列表项3");
li3.appendChild(text3);
ul.appendChild(li3);
var li4 = document.createElement("li");
var text4 = document.createTextNode("列表项4");
li4.appendChild(text4);
ul.appendChild(li4);
document.getElementsByTagName("body")[0].appendChild(ul);
</script>
</body>
</html>
第二种方法:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var ul = document.createElement("ul");
var li1 = document.createElement("li");
li1.innerHTML = "列表项1";
ul.appendChild(li1);
var li2 = document.createElement("li");
li2.innerHTML = "列表项2";
ul.appendChild(li2);
var li3 = document.createElement("li");
li3.innerHTML = "列表项3";
ul.appendChild(li3);
var li4 = document.createElement("li");
li4.innerHTML = "列表项4";
ul.appendChild(li4);
document.getElementsByTagName("body")[0].appendChild(ul);
</script>
</body>
</html>
第三种方法:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var ul = document.createElement("ul");
var li1 = "<li>列表项1</li>";
var li2 = "<li>列表项2</li>";
var li3 = "<li>列表项3</li>";
var li4 = "<li>列表项4</li>";
ul.innerHTML = li1 + li2 + li3 + li4;
document.getElementsByTagName("body")[0].appendChild(ul);
</script>
</body>
</html>
案例演示2:创建一个ul列表,里边有四个li子元素,删除第一个li,替换最后一个li
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul">
<li id="first">列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
<li id="last">列表项4</li>
</ul>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var ul = document.getElementById("ul");
var first = document.getElementById("first");
var last = document.getElementById("last");
/*删除第一个*/
ul.removeChild(first);
/*替换最后一个*/
var replaceLi = document.createElement("li");
replaceLi.innerHTML = "列表4的替换";
ul.replaceChild(replaceLi, last);
</script>
</body>
</html>
案例演示3:创建一个ul列表,里边有四个li子元素,在第一个li前边插入一个id为zero的li
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul">
<li id="first">列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
<li>列表项4</li>
</ul>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var ul = document.getElementById("ul");
var first = document.getElementById("first");
var zero = document.createElement("li");
zero.innerHTML = "列表0的新增";
ul.insertBefore(zero, first);
</script>
</body>
</html>
3.5 查找 HTML 父子
3.5.1 方法介绍
3.5.2 方法演示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box">
<ul id="ul">
<li><a href="https://www.baidu.com">我是超链接1</a></li>
<li id="two"><a href="https://www.baidu.com">我是超链接2</a></li>
<li><a href="https://www.baidu.com">我是超链接3</a></li>
<li><a href="https://www.baidu.com">我是超链接4</a></li>
</ul>
</div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
var ul = document.getElementById("ul");
var two = document.getElementById("two");
console.log(ul.parentNode);
console.log(ul.parentElement);
console.log("===============");
console.log(box.childNodes);
console.log(box.children);
console.log("===============");
console.log(ul.firstChild);
console.log(ul.firstElementChild);
console.log(ul.lastChild);
console.log(ul.lastElementChild);
console.log("===============");
console.log(two.previousSibling);
console.log(two.previousElementSibling);
console.log(two.nextSibling);
console.log(two.nextElementSibling);
</script>
</body>
</html>
4、DOM文档事件
4.1 事件概述
HTML事件可以触发浏览器中的行为,比方说当用户点击某个 HTML 元素时启动一段 JavaScript。
4.2 窗口事件
由窗口触发该事件 (同样适用于 <body> 标签):
案例演示1:当窗口失去焦点时,输出“窗口失去焦点”
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
window.onblur = function () {
console.log("窗口失去焦点");
};
</script>
</body>
</html>
案例演示2:当窗口获取焦点时,输出“窗口获取焦点”
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
window.onfocus = function () {
console.log("窗口获取焦点");
};
</script>
</body>
</html>
案例演示3:当页面文档加载完成后,输出"Hello, World"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
window.onload = function () {
console.log("Hello,World");
};
</script>
</body>
</html>
案例演示4:当调整窗口大小时,输出"窗口大小正在改变"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
window.onresize = function () {
console.log("窗口大小正在改变");
};
</script>
</body>
</html>
4.3 表单事件
表单事件在HTML表单中触发 (适用于所有 HTML 元素,但该HTML元素需在form表单内):
案例演示1:当文本框获取焦点,文本框背景为红色,当文本框失去焦点,文本框背景为黄色
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 当文本框获取焦点,文本框背景为红色 */
textInput.onfocus = function () {
this.style.background = "red";
};
/* 当文本框失去焦点,文本框背景为绿色 */
textInput.onblur = function () {
this.style.background = "green";
};
</script>
</body>
</html>
注意:这里为什么要用this,你不用this也可以,就直接
textInput.style.background = "red";
也不是不可以的,但是方法的调用规则就是谁调用this,this就指向谁,这样我们就可以简化代码了
案例演示2:当文本框内容改变时,鼠标离开文本框,自动将文本框的内容输出到控制台
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 当文本框内容改变时,鼠标离开文本框,自动将文本框的内容输出到控制台 */
textInput.onchange = function () {
console.log(this.value);
};
</script>
</body>
</html>
案例演示3:当文本框内容改变时,立即将改变的内容输出到控制台
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 当文本框内容改变时,立即将改变的内容输出到控制台 */
textInput.oninput = function () {
console.log(this.value);
};
</script>
</body>
</html>
案例演示4:如果单击“submit”,则不填写文本字段,将发生警报消息
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text" required>
<input type="submit" value="submit">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 如果单击“submit”,则不填写文本字段,将发生警报消息 */
textInput.oninvalid = function () {
console.log("请您完善表单内容!");
};
</script>
</body>
</html>
案例演示5:当选中文本框的内容时,输出“您已经选择了文本框内容!”
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 当选中文本框的内容时,输出“您已经选择了文本框内容!” */
textInput.onselect = function () {
console.log("您已经选择了文本框内容!");
};
</script>
</body>
</html>
案例演示6:当提交表单的时候,在控制台输出“表单提交”
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form id="myform">
<input type="submit" id="submit">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var myform = document.getElementById("myform");
/* 当提交表单的时候,在控制台输出“表单提交” */
myform.onsubmit = function () {
console.log("表单提交");
return false;/* 用来阻止表单提交的,你不写它会跳转请求 */
};
</script>
</body>
</html>
4.4 键盘事件
通过键盘触发事件,类似用户的行为:
案例演示1:当键盘按下判断当前的按键是不是 a ,如果是就输出true,否则输出false
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
/* 当键盘按下判断当前的按键是不是 a ,如果是就输出true,否则输出false */
window.onkeydown = function (event) {
/* 解决兼容性问题 */
event = event || window.event;
if (event.keyCode == 65) {
console.log("true");
} else {
console.log("false");
}
};
</script>
</body>
</html>
案例演示2:使div可以根据不同的方向键向不同的方向移动
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
//为document绑定一个按键按下的事件
document.onkeydown = function (event) {
event = event || window.event;
// 定义移动速度
var speed = 10;
// 选择移动方向
switch (event.keyCode) {
case 37:
box.style.left = box.offsetLeft - speed + "px";
break;
case 39:
box.style.left = box.offsetLeft + speed + "px";
break;
case 38:
box.style.top = box.offsetTop - speed + "px";
break;
case 40:
box.style.top = box.offsetTop + speed + "px";
break;
}
};
</script>
</body>
</html>
4.5 鼠标事件
通过鼠标触发事件,类似用户的行为:
案例演示1:创建一个正方形div,默认颜色为黑色,当鼠标移入div,背景颜色变为红色,当鼠标移出div,背景颜色变为绿色
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box" style="width: 100px;height: 100px;background: black;"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
/* 当鼠标移入div,背景颜色变为红色 */
box.onmouseenter = function () {
this.style.background = "red";
};
/* 当鼠标移出div,背景颜色变为绿色 */
box.onmouseleave = function () {
this.style.background = "green";
};
</script>
</body>
</html>
4.6 媒体事件
通过视频(videos),图像(images)或音频(audio) 触发该事件。
七、JavaScript BOM
1、BOM概述
浏览器对象模型(BOM)使 JavaScript 有能力与浏览器"对话"。
浏览器对象模型(Browser Object Model (BOM))尚无正式标准。
由于现代浏览器已经(几乎)实现了 JavaScript 交互性方面的相同方法和属性,因此常被认为是BOM的方法和属性。
浏览器对象模型(BOM)可以使我们通过JS来操作浏览器,在BOM中为我们提供了一组对象,用来完成对浏览器的操作,常见的BOM对象如下:
- Window:代表的是整个浏览器的窗口,同时window也是网页中的全局对象
- Navigator:代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
- Location:代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
- History:代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录,由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当次访问时有效
- Screen:代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用
2、Window对象
2.1 弹出框
JavaScript 有三种类型的弹出框:警告框、确认框和提示框。
2.1.1 警告框
如果要确保信息传递给用户,通常会使用警告框。当警告框弹出时,用户将需要单击“确定”来继续。
语法:
window.alert("sometext");
注意:window.alert() 方法可以不带 window 前缀来写。
实例
alert("我是一个警告框!");
2.1.2 确认框
如果您希望用户验证或接受某个东西,则通常使用“确认”框。
当确认框弹出时,用户将不得不单击“确定”或“取消”来继续进行。
如果用户单击“确定”,该框返回 true。如果用户单击“取消”,该框返回 false。
语法
window.confirm("sometext");
注意:window.confirm() 方法可以不带 window 前缀来编写。
实例
var r = confirm("请按按钮");
if (r == true) {
x = "您按了确认!";
} else {
x = "您按了取消!";
}
2.1.3 提示框
如果您希望用户在进入页面前输入值,通常会使用提示框。
当提示框弹出时,用户将不得不输入值后单击“确定”或点击“取消”来继续进行。
如果用户单击“确定”,该框返回输入值。如果用户单击“取消”,该框返回 NULL。
语法
window.prompt("sometext","defaultText");
window.prompt() 方法可以不带 window 前缀来编写。
实例
var person = prompt("请输入您的姓名", "比尔盖茨");
if (person != null) {
console.log(person);
}
2.2 定时事件
JavaScript 可以在时间间隔内执行,这就是所谓的定时事件( Timing Events)。
window 对象允许以指定的时间间隔执行代码,这些时间间隔称为定时事件。
通过 JavaScript 使用的有两个关键的方法:
- setTimeout(function, milliseconds)
- 在等待指定的毫秒数后执行函数。
- setInterval(function, milliseconds)
- 等同于 setTimeout(),但持续重复执行该函数。
setTimeout() 和 setInterval() 都属于 window 对象的方法。
2.2.1 延时器
setTimeout() 方法:延时器
window.setTimeout(function, milliseconds);
注意:window.setTimeout() 方法可以不带 window 前缀来编写。
- 第一个参数是要执行的函数。
- 第二个参数指示执行之前的毫秒数。
案例演示:单击按钮,等待 3 秒,然后控制台会输出 "Hello"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementById("btn");
btn.onclick = function () {
// 创建延时器
var timer = setTimeout(function () {
console.log("Hello");
}, 3000);
// 清除延时器
// clearTimeout(timer);
};
</script>
</body>
</html>
2.2.2 定时器
setInterval() 方法:定时器
setInterval() 方法在每个给定的时间间隔重复给定的函数。
window.setInterval(function, milliseconds);
注意:window.setInterval() 方法可以不带 window 前缀来写。
- 第一个参数是要执行的函数。
- 第二个参数每个执行之间的时间间隔的长度。
案例演示:单击按钮,每隔一秒向控制台输出 "Hello"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">按钮</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn = document.getElementById("btn");
btn.onclick = function () {
// 创建定时器
var timer = setInterval(function () {
console.log("Hello");
}, 1000);
// 清除定时器
// clearInterval(timer);
};
</script>
</body>
</html>
2.3 常用窗口属性
两个属性可用用于确定浏览器窗口的尺寸。
这两个属性都以像素返回尺寸:
- window.innerHeight - 浏览器窗口的内高度(以像素计)
- window.innerWidth - 浏览器窗口的内宽度(以像素计)
浏览器窗口(浏览器视口)不包括工具栏和滚动条。
对于 Internet Explorer 8, 7, 6, 5:
- document.documentElement.clientHeight
- document.documentElement.clientWidth
或
- document.body.clientHeight
- document.body.clientWidth
一个实用的 JavaScript 解决方案(包括所有浏览器):该例显示浏览器窗口的高度和宽度(不包括工具栏和滚动条)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var w = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
console.log(w);
console.log(h);
</script>
</body>
</html>
2.4 其它窗口方法
window.open() :打开新的窗口
语法介绍:
window.open(URL,name,specs,replace);
参数介绍:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button onclick="openWin()">打开窗口</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
function openWin() {
myWindow = window.open('', '', 'width=200,height=100');
myWindow.document.write("<p>这是新建窗口</p>");
}
</script>
</body>
</html>
window.close() :关闭当前窗口
语法介绍:
window.close();
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button onclick="openWin()">打开窗口</button>
<button onclick="closeWin()">关闭窗口</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
function openWin() {
myWindow = window.open('', '', 'width=200,height=100');
myWindow.document.write("<p>这是新建窗口</p>");
}
function closeWin() {
myWindow.close();
}
</script>
</body>
</html>
window.moveTo() :移动当前窗口
语法介绍:
window.moveTo(x,y);
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button onclick="openWin()">打开窗口</button>
<button onclick="moveWin()">移动窗口</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
function openWin() {
myWindow = window.open('', '', 'width=200,height=100');
myWindow.document.write("<p>这是新建窗口</p>");
}
function moveWin() {
myWindow.moveTo(300, 300);
myWindow.focus();
}
</script>
</body>
</html>
window.resizeTo() :调整当前窗口
语法介绍
window.resizeTo(width,height);
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button onclick="openWin()">打开窗口</button>
<button onclick="resizeWin()">调整窗口</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
function openWin() {
myWindow = window.open('', '', 'width=200,height=100');
myWindow.document.write("<p>这是新建窗口</p>");
}
function resizeWin() {
myWindow.resizeTo(300, 300);
myWindow.focus();
}
</script>
</body>
</html>
3、Navigator对象
Navigator代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器,由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了,一般我们只会使用userAgent来判断浏览器的信息,userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的userAgent,如下代码:
var ua = navigator.userAgent;
console.log(ua);
是乎,我们就可以实现对浏览器类型的判断:
var ua = navigator.userAgent;
if (/firefox/i.test(ua)) {
alert("你是火狐浏览器");
} else if (/chrome/i.test(ua)) {
alert("你是谷歌浏览器");
} else if (/msie/i.test(ua)) {
alert("你是IE5-IE10浏览器");
} else if ("ActiveXObject" in window) {
alert("你是IE11浏览器");
}
4、Location对象
Location对象中封装了浏览器的地址栏的信息,如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
4.1 常用属性
console.log(location); //输出location对象
console.log(location.href); //输出当前地址的全路径地址
console.log(location.origin); //输出当前地址的来源
console.log(location.protocol); //输出当前地址的协议
console.log(location.hostname); //输出当前地址的主机名
console.log(location.host); //输出当前地址的主机
console.log(location.port); //输出当前地址的端口号
console.log(location.pathname); //输出当前地址的路径部分
console.log(location.search); //输出当前地址的?后边的参数部分
修改地址:
location = "https://www.baidu.com";
location.href = "https://www.baidu.com";
4.2 常用方法
assign():用来跳转到其它的页面,作用和直接修改location一样
location.assign("https://www.baidu.com");
reload():用于重新加载当前页面,作用和刷新按钮一样,如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
location.reload(true);
replace():可以使用一个新的页面替换当前页面,调用完毕也会跳转页面,它不会生成历史记录,不能使用回退按钮回退
location.replace("https://www.baidu.com");
5、History对象
History对象可以用来操作浏览器向前或向后翻页
5.1 常用属性
console.log(history); //输出history对象
console.log(history.length); //可以获取到当成访问的链接数量
5.2 常用方法
back():可以回退到上一个页面,作用和浏览器的回退按钮一样
history.back();
forward():可以跳转到下一个页面,作用和浏览器的前进按钮一样
history.forward();
go():可以用来跳转到指定的页面,它需要一个整数作为参数
- 1:表示向前跳转一个页面,相当于forward()
- 2:表示向前跳转两个页面
- -1:表示向后跳转一个页面,相当于back()
- -2:表示向后跳转两个页面
history.go(-2);
6、Screen对象
Screen 对象包含有关客户端显示屏幕的信息。
注意:没有应用于 screen 对象的公开标准,不过所有浏览器都支持该对象。
6.1 Screen对象描述
每个 Window 对象的 screen 属性都引用一个 Screen 对象。Screen 对象中存放着有关显示浏览器屏幕的信息。JavaScript 程序将利用这些信息来优化它们的输出,以达到用户的显示要求。例如,一个程序可以根据显示器的尺寸选择使用大图像还是使用小图像,它还可以根据显示器的颜色深度选择使用 16 位色还是使用 8 位色的图形。另外,JavaScript 程序还能根据有关屏幕尺寸的信息将新的浏览器窗口定位在屏幕中间。