js&ES

JavaScript详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pXteuBCX-1679284523312)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1666941289402.png)]

1 js特点

1.1 解释型语言

编译型语言

程序在执行之前需要一个专门的编译过程,把程序编译为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、Delphi等。

解释型语言

程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。如 Python、Shell、JavaScript 等。

1.2 弱类型语言

没有明确的类型声明,同一用 var、let、count这是三个关键字声明变量、动态的变量类型,如 var a = 5;a = ‘liang’,输出a的值就是 ‘liang’;

强类型语言:C/C++、Java等

类似于 C 和 Java 的语法结构

顺序、选择、循环,编程语言的通用语法结构

1.3 基于原型的面向对象

JavaScript是一门面向对象的语言,也可以基于函数编程(面向过程)

但是与强类型不同JavaScript是基于原型(prototype)的面向对象、而非基于类(class)

2 js使用

  • html文件内标签引用
<script>
    alert("Hello,World!");
</script>
  • js文件引用
<script src="main.js"></script>

3 js基础语法

标识符:驼峰命名

3.1 数据类型

3.1.1 String(略)
3.1.2 Number
  • 最大值:+1.7976931348623157e+308
  • 最小值:-1.7976931348623157e+308

特殊数字:

  • Infinity:正无穷
  • -Infinity:负无穷
  • NaN:非法数字(Not A Number)
3.1.3 Boolean(略)
3.1.4 Undefined

只有一个值 undefined ,未初始化的变量也是undefined

3.1.5 Null

只有一个值 null,用typeof 检测返回object

undefined值实际上是由null值衍生出来的

(undefined==null)=>true

(undefined===null)=>false

3.1.6 检测类型 typeof type
        var a = 'jack'
        var b = 123
        var c = true
        var d = null
        var e = undefined
        console.log(typeof a)
        console.log(typeof b)
        console.log(typeof c)
        console.log(typeof d)
        console.log(typeof e)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jMXn8Qxr-1679284523313)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1675256595525.png)]

3.2 类型转换

3.2.1 转换为String

(1)toString();

var a = 100;
a=a.toString()
console.log(typeof a)
// 会发现已经转为String类型

(2)调用String()函数

var a = 123;
a = String(a);
console.log(a);
console.log(typeof a);
// 会发现已经转为String类型

(3)数据类型+“”(数据类型+(空)字符串)

var a = 123;
a = a + "";
console.log(a);
console.log(typeof a);
3.2.2 转换为Number类型

三个转数字函数:

  • Number():任意类型转换为数字
  • parseInt() / parseFloat():字符串转换为数字 (整型/浮点型)
Number():

(1)String=》Number

  • 数字字符串会直接转为数字

  • 字符串中含有非数字字符会转换为NaN

  • 字符串含有一个空串或是一个全是空格的字符串,则转换为0

(2)Boolean=>Number

true=>1; false=>0

(3) null=>0

(4) undefined=>NaN

parseInt() / parseFloat():

这两个函数都是匹配字符串中有效的数字字符串

var a = "123";
a = parseInt(a);
console.log(a);
console.log(typeof a);

var a = "123.456";
a = parseFloat(a);
console.log(a);
console.log(typeof a);
3.2.3 转换为Boolean类型

使用Boolean()函数

Number=>Boolean:

除了0和NaN,都是true

String=>Boolean

除了空串都是true

null和undefined

(Boolean(null))=>false

(Boolean(undefined))=>false

Object=>Boolean

true

3.3 运算符

3.3.1 算数运算法:

(+ ) (-) * / % ++ –

3.3.2 关系运算符(略)
3.3.3 逻辑运算符(略)
3.3.4 比较运算符
  • ==:

二值相等运算, 如果值的类型不同,则会自动转换相同类型

比如:null== undefined==>true

  • ===

二值全等运算,要求类型相同、值相同才为true

  • !==

二值不全等运算,值相同类型不同为true

3.3.5 三元运算符

a=(flag)?b:c

flag为true,a=b, else a=c

3.4 代码块

把多条语句视为一条使用

{
    let i = 100;
    i++;
    console.log(i)
}

3.5 流程控制语句

if else

switch–case

for while/do—while

  • 循环控制:break;continue

3.6 对象

//创建方式一:
var person = new Object();
person.name = "险胜将军";
person.age = 18000;
console.log(person);

//创建方式二:
var person = {
    name: "猴子",
    age: 510
};
console.log(person);

// 属性访问,两种方式
person.name;
person['name'];

// 删除属性
delete person.age

// 遍历对象
for (var personKey in person) {
    var personVal = person[personKey];
    console.log(personKey + ":" + personVal);
}

3.7 数据类型

3.7.1 基本数据类型

String、Number、Boolean、Null、Undefined

在基本数据类型中,认为两个变量值相等,则这两个变量相等

基本数据类型的变量存在 栈内存中

3.7.2 引用数据类型
  • 当一个变量是一个对象时,实际上变量中保存的并不是对象本身,而是对象的引用。

  • 当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象。这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个。

3.8 函数

3.8.1 创建函数(三种方式)
// 方式一:使用函数对象创建(不建议)
var fn = new Function("执行语句");

// 方式二:使用函数声明创建
function fn([参数1,参数2...]){
    // 语句
}

// 方式三:使用函数表达式创建
var fn = function([参数1,参数2...]){
    // 语句
}

3.8.2 嵌套函数

嵌套函数只能在当前函数中可以访问,在当前函数外无法访问。

function fu() {
    function zi() {
        console.log("我是儿子")
    }
    zi();
}
fu();
3.8.3 立即执行函数

一旦定义成功立即被调用

(function(){
    alert('立即执行函数');
})();
3.8.4 this 对象

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象

以函数的形式调用时,this永远都是window
以方法的形式调用时,this就是调用方法的那个对象

3.9 对象进阶

3.9.1 使用工厂方法创建对象
// 多个同类型的对象可以用同一模板创建对象
// 使用这种方法创建对象,对象都是Object类型,不符合人的主观感受
function createPerson(name, age) {
    // 创建新的对象
    var obj = new Object();
    // 设置对象属性
    obj.name = name;
    obj.age = age;
    // 设置对象方法
    obj.sayName = function () {
        console.log(this.name);
    };
    //返回新的对象
    return obj;
}

var person1 = createPerson("孙悟空", 18);
var person2 = createPerson("猪八戒", 19);
var person3 = createPerson("沙和尚", 20);
3.9.2 使用构造函数创建对象

构造函数与普通函数差别不大,构造函数名约定首字母大写,且需要用new关键字调用,一旦调用即创建对象,将新创建的对象作为其返回值,保证了其灵活性

function Animal(type,name,say){
    this.name=name;
    this.type=type;
    this.say=say;
    this.sayH = function(){
        console.log(this.say);
    }
}
var d = new Animal("dog","旺财","汪汪");
var c = new Animal("cat","旺财","喵喵");
var j = new Animal("ji","ikun","叽叽");

// 考虑到并不是每个对象都有相同的方法,可以将该方法抽离到构造函数外部成为全局函数,
function Animal(type,name,say){
    this.name=name;
    this.type=type;
    this.say=say;
    this.sayH = sayH
}
function sayH(){
    console.log(this.say);
}
var d = new Animal("dog","旺财","汪汪");
var c = new Animal("cat","旺财","喵喵");
var j = new Animal("ji","ikun","叽叽");

//但是作为全局函数不妥当,容易污染全局作用域, 原型对象
function Animal(type,name,say){
    this.name=name;
    this.type=type;
    this.say=say;
}
Animal.prototype.sayH=function(){
    console.log(this.say);
}
var d = new Animal("dog","旺财","汪汪");
var c = new Animal("cat","旺财","喵喵");
var j = new Animal("ji","ikun","叽叽");

  • 原型(prototype)到底是什么呢?

我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象,即显式原型,原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。

如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__(隐式原型)来访问该属性。当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。

以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。

原文链接:https://blog.csdn.net/qq_38490457/article/details/109257751

3.9.3 原型链

访问一个对象的属性时,先在自身属性中查找,找到返回, 如果没有,再沿着__proto__这条链向上查找,找到返回,如果最终没找到,返回undefined,这就是原型链,又称隐式原型链,它的作用就是查找对象的属性(方法)。

3.9.4 in

使用in检测对象是否存在某个属性,但是对象没有而原型对象有该属性仍然返回true,可使用对象的hasOwnProperty()方法,hasOwnProperty属于原型对象的属性

console.log("name" in person)
console.log(person.hasOwnProperty("name"))
3.9.4 this对象梳理:
  • 当以函数的形式调用时,this是window
  • 当以方法的形式调用时,谁调用方法this就是谁
  • 当以构造函数的形式调用时,this就是新创建的那个对象

可以使用 instanceof 运算符检查一个对象是否是一个类的实例,它返回true或false

console.log(d instanceof Animal)
3.9.5 对象继承(待续…)
3.9.6 遍历对象
var obj ={
    name:'liang',
    age:18,
    sex:'男'
};
// for...in遍历对象属性名
for(var key in obj){
    console.log(key);  //遍历对象属性名
    console.log(obj[key]); // 遍历属性值
}

3.10 垃圾回收

JS中有自动的垃圾回收机制,自动将垃圾对象从内存中销毁,程序员不需要也不能进行垃圾回收的操作,只需将不再使用的对象设置null即可

3.11 作用域

3.11.1 全局作用域
  • 直接编写在script标签中的JavaScript代码,都在全局作用域
  • 全局作用域在页面打开时创建,在页面关闭时销毁
  • 全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建,我们可以直接使用
  • 在全局作用域中 变量都会作为window对象的属性保存 函数都会作为window对象的方法保存
3.11.2 函数作用域
  • 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
  • 每调用一次函数就会创建一个新的函数作用域,它们之间是互相独立的
  • 在函数中要访问全局变量可以使用window对象
  • 作用域链:当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错ReferenceError

4 常用的 JS 对象

4.1 数组对象

// 使用对象创建数组
var a = new Array();
a[0]=1;
a[1]=2;
......

// 使用字面量创建对象
var a = [1,2,3,4];
// 数组元素可以是不同类型
var b = [1,2,"你好"];

// 遍历数组
for(let i = 0; i<a.lenght; i++){
    log(a[i]);
}
4.1.1 数组方法
  • push():末尾添加一个元素,返回数组长度
  • pop():删除最后一个元素,并作为函数返回值返回
  • shift():删除第一个元素,并作为返回值返回
  • unshift():在数组开头添加一个或多个元素,返回数组长度
var arr = ["孙悟空", "猪八戒", "沙和尚"];
var result = arr.unshift("牛魔王", "二郎神");
console.log(arr);
console.log(result);
  • forEach():IE8及以下不支持,用来遍历数组: 需要一个函数作为参数,像这种函数,由我们创建但是不由我们调用的,我们称为回调函数。
    • 这个回调函数的三个参数(v(元素),i(index),obj(数组对象))
var arr = ["孙悟空", "猪八戒", "沙和尚"];
arr.forEach(function (value, index, obj) {
    console.log(value + " ---- " + index + " ---- " + obj);
});
  • **join()😗*设置数组元素的间隔符,可以是字符,数字
        var a = [1, 5, 3, 4]
        b = a.join('-');
        console.log(b);
        console.log(typeof b);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-soyMOS4g-1679284523314)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1675394194422.png)]

  • slice():截取数组元素并封装到另一个数组中
var a = [1,2,3,4,5];
var b= a.slice(1,4)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhxD1ZTu-1679284523315)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663756987757.png)]

  • splice():

    • splice(i):i为索引,删除i以及后面的元素
      • i>0,从前数
      • i<0,从后数
    • slipce(i,j):删除从i开始的j个元素
    • slipce(i,j,a1,a2…):i开始的j个元素替换为[a1,a2,…]
  • concat():将两个或多个数组连接

var a = [1,2,3];
var b = [4,5,6];
var c = [7,8,9];
var d = a.concat(b,c,"100")
  • reverse() :反转原数组,原数组改变

  • **sort():**按照unicode编码排序,原数组改变

var a = [1, 5, 3, 4]
        console.log(a.sort())
        console.log(a)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DeokDeOu-1679284523319)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1675394707403.png)]

4.2 函数对象

4.2.1 call()和apply()方法
  • 相同点:改变this的指向
function fn(){
    console.log('我的this是'+this);
}
var fn2 = function(){
    console.log('我的this是'+this);
}

fn();
fn.call(fn2);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yd0DUYll-1679284523322)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663760692044.png)]

  • call()和apply()的区别:
    • call()方法的参数可以按顺序依次填写
    • apply()方法需要将实参封装到数组中
// 二者作用相同
fn.call(obj,v1,v2,v3...)
fn.apply(obj,[v1,v2,v3...])
4.2.2 this 指向再梳理
  • 以函数形式调用时,this永远都是window
  • 以方法的形式调用时,this是调用方法的对象
  • 以构造函数的形式调用时,this是新创建的那个对象
  • 使用call和apply调用时,this是传入的那个指定对象
4.2.3 arguments参数

调用函数时,浏览器会传递this和arguments 两个参数

  • this:函数上下文对象
  • arguments:封装实参的对象

4.3 Date对象(待续)

4.4 Math 对象(待续)

Math对象不是一个构造函数,所有方法都是静态的,直接调用即可

  • Math.floor():向下取整

  • Math.ceil():向上取整

  • Math.abs():取绝对值

  • Math.random():返回一个随机的小数[0,1)

    // 返回两个整数之间的随机整数(包含头尾)
    function getRandom(min,max){
        return Math.floor(Math.random()*(max-min+1))+min;
    }
    console.log(getRandom(1,100));
    
  • ·······

5 正则表达式(待续)

5.1 正则表达式基础

5.1.1 元字符
符号说明示例
.匹配除换行符以外的任意字符
[]匹配括号内的任意字符
*匹配重复零次或多次
+重复一次或多次
重复零次或一次
{n}重复n次
{n,}至少重复n次
{,m}最多重复m次
{n,m}重复n~m次

5.1 正则表达式对象

/*
1
*/
//方式一(构造函数创建,变量为字符串,灵活)   
// 创建正则表达式对象RegExp("正则表达式","匹配模式")两个参数
        let reg = new RegExp("a","i"); //忽略大小写查找a
        console.log(reg.test("Bca"));

// 方式2(简单便捷,变量定死不灵活)
 // 使用字面量创建正则表达式对象
        reg = /a/i;
        console.log(reg.test("Bca"));


/*
2 创建一个正则表达式,检测字符串是否有a或者b
*/
reg = /a|b/;
console.log(reg.test("bDca"));

/*
3 检查一个字符串中是否有字母 []与| 都是或的意思
*/
reg = /[A-z]/
console.log(reg.test("12456516gK231"));

/*
4 检测一个字符串中是否含有abc或bcd或cde
*/
reg = /a[bde]c/;
console.log(reg.test("badcd"));

/*

*/




6 DOM (Document Object Model)

6.1 DOM操作

6.1.1查找DOM元素:
  • document.getElementById(id)
  • document.getElementsByTagName(name)
  • document.getElementsByClassName(name)
  • document.querySelector(CSS选择器) :同类型第一个
  • document.querySelectorAll(CSS选择器) :同类型全部
6.1.2 获取DOM元素的值
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="btn" style="background: red;width: 200px;height: 200px;" class="app">
    <button >我是按钮</button>
    <p>jfdnvjdfnbjdn</p>
</div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var btn = document.getElementById("btn");
    console.log("==============================");
    console.log(btn.innerText);
    console.log("==============================");
    console.log(btn.innerHTML);
    console.log("==============================");
    console.log(btn.getAttribute("class"));//
    console.log("==============================");
    console.log(btn.style);
</script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8d2gAmJR-1679284523324)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663762989573.png)]

6.1.3 改变DOM元素
<div id="btn" style="background: red;width: 200px;height: 200px;" class="app">
    <button onclick="handleClick">我是按钮</button>
</div>

<script>
  	var btn2 = document.getElementById("btn");
    btn2.innerText="点击按钮";
    btn2.setAttribute("class","app2");
    btn2.style.background="green";
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8wGEAW5z-1679284523326)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663764323370.png)]

6.1.4 修改html元素
  • document.createElement(“ul”):创建元素节点
  • document.createAttribute(attribute) :创建元素节点属性
  • document.createTextNode(text) : 创建 HTML 文本节点。
  • 元素节点.removeChild(element) : 删除 HTML 元素。
  • 元素节点.appendChild(element) : 添加 HTML 元素。
  • 元素节点.replaceChild(element) : 替换 HTML 元素。
  • 元素节点.insertBefore(element) : 在指定的子节点前面插入新的子节点。

四大名著书架

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .book {
            color: red;
        }
    </style>
</head>
<body>

<ul id="ui" class="uul">
    <li class="book">三国演义</li>
    <li class="book">水浒传</li>
    <li class="book">西游记</li>
</ul>

<button id="add" onclick="addBook()">点击增加红楼梦</button>
<button id="color" onclick="changeColor()">点击颜色变绿</button>
<button id="sub" onclick="deleteBook()">点击删除水浒传</button>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>

<!--    点击增加红楼梦-->
    let Book = document.getElementById("ui");
    function addBook(){
        let i = 0;
        while(1){
            i++;
            if(i===Book.children.length)break;
            if(Book.children[i].innerHTML==="红楼梦"){
                break;
            }
        }
        if(i===Book.children.length){
            let newLi = document.createElement("li");
            let newText = document.createTextNode("红楼梦");
            newLi.setAttribute("class","book");
            newLi.appendChild(newText);
            Book.appendChild(newLi);
        }else alert("已经有红楼梦");

    }

//    点击颜色变绿
    let color  = document.getElementById("color");
    function changeColor(){
        // 第一次尝试:给每个li 元素添加id 属性
        // let newColor1 = document.getElementById("c1");
        // newColor1.style.color= "green";
        // 优化: 将属性写进循环
        let uul = document.getElementById("ui");
        for(let i = 0;i<uul.children.length;i++){
            uul.children[i].setAttribute("id","id"+i);
            let newColor = document.getElementById("id"+i);
            newColor.style.color = "green";
        }
    }

//点击删除水浒传
    function deleteBook(){
        let uul = document.getElementById("ui");
        let i = 0;
        while (1){
            i++;
            if(uul.children[i].innerHTML==="水浒传"){
                uul.removeChild(uul.children[i]);
                break;
            }else if(i===uul.children.length){
                alert("没有水浒传!");
                break;
            }
        }
    }

</script>
</body>
</html>

6.1.5 查找HTML父子兄弟元素
<!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>


<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); //返回元素的一个子节点的数组(包含空白文本Text节点)
    console.log(box.children); //返回元素的一个子元素的集合(不包含空白文本Text节点)
    console.log("===============");

    console.log(ul.firstChild); // 返回元素的第一个子节点(包含空白文本Text节点)
    console.log(ul.firstElementChild);//返回元素的第一个子元素(不包含空白文本Text节点)
    console.log(ul.lastChild);//返回元素的最后一个子节点(包含空白文本Text节点)
    console.log(ul.lastElementChild);//返回元素的最后一个子元素(不包含空白文本Text节点)
    console.log("===============");

    console.log(two.previousSibling);//返回某个元素紧接之前节点(包含空白文本Text节点)
    console.log(two.previousElementSibling);//返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)
    console.log(two.nextSibling); //返回某个元素紧接之后节点(包含空白文本Text节点)
    console.log(two.nextElementSibling);//返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)
</script>
</body>
</html>

案例演示(略)

6.2 DOM文档事件

6.2.1 窗口事件
  • onblur: 窗口失去焦点时

  • onfocus: 窗口获得焦点时

  • onload: 文档加载时

  • onresize: 窗口大小改变时

  • onstorage: 内存空间数据发生变化时

    window.onblur = function (){
        alert("窗口失去焦点")
    };
    window.onfocus = function (){
        alert("窗口获得焦点")
    }
	window.onload = function () {
        console.log("Hello,World");
    };
	window.onresize = function () {
        console.log("窗口大小正在改变");
    };
6.2.2 表单事件
  • onblur:失去焦点时
  • onfocus:获得焦点时
  • onchange:元素改变时
  • oninput:输入时
  • oninvalid:元素无效时
  • onselect:选取元素时
  • onsubmit:提交表单时

演示(略)

6.2.3 键盘事件
  • onkeydown :按下按键时
  • onkeyup:松开按键时
  • onkeypress:按下并松开按键时
6.2.4 鼠标事件
  • onclick:点击时
  • ondbclick:双击时
  • onmousedown:按下时
  • onmouseup:松开时
  • onmousemove:指针移动时
  • onmouseover : 指针移至元素之上时运行脚本,不可以阻止冒泡
  • onmouseout : 指针移出元素时运行脚本,不可以阻止冒泡
  • onmouseenter : 指针移至元素之上时运行脚本,可以阻止冒泡
  • onmouseleave : 指针移出元素时运行脚本,可以阻止冒泡
  • onmousewheel : 转动鼠标滚轮时运行脚本
  • onscroll : 滚动元素的滚动条时运行脚本
案例:可以自由拖动的div
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box1" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<div id="box2" style="width: 100px;height: 100px;background: green;position: absolute;"></div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");

    drag(box1);
    drag(box2);

    /*
     * 提取一个专门用来设置拖拽的函数
     * 参数:开启拖拽的元素
     */
    function drag(obj) {
        //当鼠标在被拖拽元素上按下时,开始拖拽
        obj.onmousedown = function (event) {
            // 解决事件的兼容性问题
            event = event || window.event;

            // 设置obj捕获所有鼠标按下的事件
            /**
             * setCapture():
             * 只有IE支持,但是在火狐中调用时不会报错,
             * 而如果使用chrome调用,它也会报错
             */
            obj.setCapture && obj.setCapture();

            // obj的偏移量 鼠标.clentX - 元素.offsetLeft
            // obj的偏移量 鼠标.clentY - 元素.offsetTop
            var ol = event.clientX - obj.offsetLeft;
            var ot = event.clientY - obj.offsetTop;

            // 为document绑定一个鼠标移动事件
            document.onmousemove = function (event) {
                // 解决事件的兼容性问题
                event = event || window.event;
                // 当鼠标移动时被拖拽元素跟随鼠标移动
                // 获取鼠标的坐标
                var left = event.clientX - ol;
                var top = event.clientY - ot;
                // 修改obj的位置
                obj.style.left = left + "px";
                obj.style.top = top + "px";
            };

            // 为document绑定一个鼠标松开事件
            document.onmouseup = function () {
                // 取消document的onmousemove事件
                document.onmousemove = null;
                // 取消document的onmouseup事件
                document.onmouseup = null;
                // 当鼠标松开时,取消对事件的捕获
                obj.releaseCapture && obj.releaseCapture();
            };

            /*
             * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
             * 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
             * 如果不希望发生这个行为,则可以通过return false来取消默认行为,
             * 但是这招对IE8不起作用
             */
            return false;
        };
    }
</script>
</body>
</html>
6.2.5 媒体事件
  • onabort: 当发生中止事件时运行脚本。
  • oncanplay: 当媒介能够开始播放但可能因缓冲而需要停止时运行脚本。
  • oncanplaythrough: 当媒介能够无需因缓冲而停止即可播放至结尾时运行脚本。
  • ondurationchange: 当媒介长度改变时运行脚本。
  • onemptied: 当媒介资源元素突然为空时(网络错误、加载错误等)运行脚本。
  • onended: 当媒介已抵达结尾时运行脚本。
  • onerror: 当在元素加载期间发生错误时运行脚本。
  • onloadeddata: 当加载媒介数据时运行脚本。
  • onloadedmetadata: 当媒介元素的持续时间以及其它媒介数据已加载时运行脚本。
  • onloadstart: 当浏览器开始加载媒介数据时运行脚本。
  • onpause: 当媒介数据暂停时运行脚本。
  • onplay: 当媒介数据将要开始播放时运行脚本。
  • onplaying: 当媒介数据已开始播放时运行脚本。
  • onprogress: 当浏览器正在取媒介数据时运行脚本。
  • onratechange: 当媒介数据的播放速率改变时运行脚本。
  • onreadystatechange: 当就绪状态(ready-state)改变时运行脚本。
  • onseeked: 当媒介元素的定位属性不再为真且定位已结束时运行脚本。
  • onseeking: 当媒介元素的定位属性为真且定位已开始时运行脚本。
  • onstalled: 当取回媒介数据过程中(延迟)存在错误时运行脚本。
  • onsuspend: 当浏览器已在取媒介数据但在取回整个媒介文件之前停止时运行脚本。
  • ontimeupdate: 当媒介改变其播放位置时运行脚本。
  • onvolumechange: 当媒介改变音量亦或当音量被设置为静音时运行脚本。
  • onwaiting: 当媒介已停止播放但打算继续播放时运行脚本。

6.3 DOM事件高级

  • 元素注册事件的两种方式

  • 删除事件的两种方式

  • DOM事件流 的三个阶段

  • 利用事件对象完成鼠标跟随案例

  • 封装阻止冒泡的兼容性函数

  • 事件委托的原理

6.3.1 注册事件

传统方式:

  • 利用on开头的事件,比如onclick
  • 特点:注册事件的唯一性
 <button>传统注册事件</button>
    <script>
        // 同一个元素同一个事件只能设置一个处理函数,后面覆盖前面
        let btns = document.querySelectorAll("button");
        btns[0].onclick = ()=>alert("hello,传统注册事件");
        // 这个事件覆盖了上面的事件
        btns[0].onclick = ()=>alert("hello,传统注册事件222");
	</script>

方法监听注册事件:

  • W3C标准推荐方式
  • 语法:addEventListener(type,listener[,useCapture])
    • type:事件类型字符串,如"click"、"mouseover"等(前面没有“on”)
    • listener:事件处理函数,事件发生时调用
    • useCapture:可选布尔值参数,默认false;后续会学(待续)
  • IE9之前需要使用attachEvent()
  • 特点:同一元素同一事件可以设置多个处理程序,按顺序执行
 <button>传统注册事件</button> 
<button>方法监听注册事件</button>
    
    <script>
// 下面两个事件顺序发生
        btns[1].addEventListener("click",function(){
            alert("事件监听注册事件");
        });
        btns[1].addEventListener("click",function(){
            alert("事件监听注册事件222222");
        });


    </script>
6.3.2 删除事件

事件置空即可:eventTarget.onclick = null;

 	<div>1</div>
    <div>2</div>
    <div>3</div>

<script>
    //传统删除事件: 事件置空即可:
    // eventTarget.onclick = null;
        let divs = document.querySelectorAll("div");
        divs[0].onclick = function(){
            alert("hello,div1");
             // 删除事件
            divs[0].onclick = null;
        };
    
	// 方法监听注册事件的删除:
    // removeEventListener(type,listener[,useCapture])
    // 事件处理函数建议写在外部
        divs[1].addEventListener("click",fnDiv1);
        function fnDiv1(){
            alert("hello,div2");
            // 删除事件
            divs[1].removeEventListener("click",fnDiv1);
        }

</script>
6.3.3 DOM事件流

事件流描述的是页面接收事件的顺序,分为捕获阶段冒泡阶段

事件冒泡: 子元素事件发生时,父元素的相同事件也会触发

捕获阶段:document->html->body->元素

冒泡阶段:元素->body->html->document

方法:addEventListener(type,function, useCapture);

布尔值useCapture

  • true:事件捕获,同种事件(如点击):先父后子
  • false(默认):事件冒泡,同种事件(如点击):先子后父
<style>
        .father {
            height: 400px;
            width: 400px;
            background-color: aquamarine;
        }
        .son {
            height: 200px;
            width: 200px;
            background-color:blue;
        }
    </style>
<div class="father">
        <div class="son"></div>
    </div>
    
    <script>
        let father  = document.querySelector(".father");
        father.addEventListener("click",()=>{alert("div father!")},true);

        let son  = document.querySelector(".son");
        son.addEventListener("click",()=>{alert("div son!")},true);
    </script>

没有冒泡的事件:onblur、onfocus、onmouseenter、onmouseleave等

6.3.4 事件对象
6.3.4.1 什么是事件对象
<div></div>

    <script>
        let div  = document.querySelector("div");
        div.onclick = event=>{
            event = event ||window.event //兼容性ie678
            console.log(event);
        };
    // 参数event 就是事件对象,存在事件才会存在,系统自动创建,无需传参
    // 事件对象是事件相关数据的集合,,如点击事件,键盘事件等信息
    </script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6e7rnubr-1679284523326)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1666367126640.png)]

6.3.4.2 e.target和this的区别
  • e.target返回的是触发事件的对象,this返回的是绑定事件的对象
  • 比如给
    • 绑定点击事件,当点击
    • 元素时,e.target返回
    • ,this返回
    • e.target的兼容性:e.target||e.srcElement
6.3.4.3 阻止默认行为

默认行为就是绑定的事件应该要发生的行为,但是可能因为条件不足不允许点击效果

<script>
    // 传统方式
	a.onclick = function(e){
        // 普通浏览器,使用该方法
        e.preventDefault();
        // ie678 使用改属性
        e.returnValue;
        // return false 也可以阻止默认行为,
        return false;
    }
    
    // 监听方法方式
    a.addEventListener("click",function(e){
        // 普通浏览器,使用该方法,return false在这不管用
        e.preventDefault();
        
    })
    
</script>
6.3.5 阻止事件冒泡

当父子元素都有某同一种事件时,我们只希望子元素能够触发事件,这个时候就需要阻止冒泡

利用事件对象的方法e.stopPropagation();

<div class="father">
        <div class="son">
            子元素
        </div>
    </div>
      
    <script>
        // dom推荐 e.stopPropagation();
        let son = document.querySelector(".son");
        son.addEventListener("click",function(e){
            alert("我是子元素");
            // e.stopPropagation(); //实际开发常用
            er = e.stopPropagation()||(e.cancelBubble=true);// 兼容性,ie678
        },false);
        let father = document.querySelector(".father");
        father.addEventListener("click",function(e){
            alert("我是父元素");
            er = e.stopPropagation()||(e.cancelBubble=true);// 兼容性,ie678
        },false);
        document.addEventListener("click",function(e){
            alert("我是document")
        })

    </script>
6.3.6 事件委托

希望只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的,我们可以尝试将其绑定给元素的共同的祖先元素,也就是事件的委派。事件的委派,是指将事件统一绑定给元素的共同的祖先元素这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。事件委派是利用了事件冒泡,通过委派可以减少事件绑定的次数,提高程序的性能

<ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script>
        // 事件委托的原理:给父元素添加监听器,监听子元素
        let ul = document.querySelector("ul");
        ul.addEventListener('click',function(e){
            alert("我是委托元素ul");
        })

    </script>

6.5其他知识

6.5.2 阻止网页右键菜单或Ctrl+C/Ctrl+V

文档阻止默认行为即可,e.preventDefault();

// 阻止网页右键菜单
document.addEventListener('contextmenu',function(e){
    e.preventDefault();
});
// 阻止选中
document.addEventListener('selectstart',function(e){
    e.preventDefault();
});
6.5.3 鼠标事件对象常用属性
document.addEventListener('click',e=>{})
// e就是鼠标事件对象
// e.clientX、e.clientY:无论页面多长,都是相对于窗口的坐标
// e.pageX、e.pageY:相对于文档边缘的距离
// e.screenX、e.screenY:相对于屏幕边缘的距离
6.5.4 键盘事件对象常用属性
  • keydown(onkeydown):按下触发
  • keyup(onkeyup):松开时触发
  • keypress(onkeypress):按下时触发,但不识别功能键
// 判断用户按下哪个键
// keyup和keydown不区分字母大小写
// keypress区分字母大小写,因为...
    document.addEventListener('keyup',function(e){
            console.log(e.key); //存在兼容性问题
            console.log(e.keyCode); // 
        });

7 BOM( Browser Object Model)

常见的bom对象

  • Window:浏览器窗口,网页的全局对象
  • Navigator:当前浏览器信息
  • Location:浏览器地址栏信息, Location可以获取地址栏信息,或者操作浏览器跳转页面
  • History: 代表浏览器的历史记录
  • Screen: 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息

7.1 Window对象

js 的三种弹出框:、提示框、警告框

window.confirm("sometext"); // 确认框
window.prompt("sometext");  // 提示框(输入框)
window.alert("sometext");   // 警示框
7.1.1 定时事件

js代码在一段时间间隔内执行,即定时事件

两个关键方法:

  • setTimeout(function, milliseconds)

milliseconds毫秒之后,执行function

  • setInterval(function, milliseconds)

与setTimeout的区别是:重复执行

7.1.2 案例:延时器setTimeout(function, milliseconds)

点击按钮后三秒弹出警示框(hello)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>

</head>
<body>
<button id="btn1" onclick="sayHHH()">点击三秒弹出hello</button>

<script>
<!--setTimeout(function, milliseconds)-->

    function sayHHH(){
        var timer = window.setTimeout(sayHello,3000)
    }
    function sayHello(){
        alert("hello!")
    }
    clearTimeout(timer);
</script>
</body>
</html>

7.1.3 案例:定时器倒计时setInterval(function, milliseconds)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        ul {
            height: 100px;
            width: 300px;
            margin: 100px auto;
        }
       li {
        float: left;
        list-style: none;
        height: 100px;
        width: 100px;
        background-color: red;
        line-height: 100px;
        font-size: 70px;
        text-align: center;
       }
    </style>

</head>
<body>

    <!-- 倒计时 -->
    <ul>
        <li id = "hours"></li>
        <li id = "minute"></li>
        <li id = "second"></li>
    </ul>
    
    <button id="b1">开始倒计时</button>
    <button id="b2">停止</button>
    
    <script>
        let hours = document.querySelector("#hours");
        let minute = document.querySelector("#minute");
        let second = document.querySelector("#second");

        let b1 = document.querySelector("#b1");
        let b2 = document.querySelector("#b2");

        let inputTime = +new Date('2022-10-22 19:00');  // 输入的时间

        // 先调用一次,防止刷新的时候的第一秒没有效果
        countDown();

        //开启定时器,每隔一秒调用countDown
        let timer = null;
        b1.addEventListener('click',function(){
            // alert("nihao");
            timer = setInterval(countDown,1000);
        });
        // 点击停止 清除定时器
        b2.onclick =function(){
            clearInterval(timer);
        }
        
        // 获取倒计时时间
        function countDown(){
            // 注意time 的格式 为'2022-10-22 18:00'
            // 首先获取剩余的秒数
            let now = +new Date();
 
            let subTime = (inputTime - now)/1000; //剩余秒数

            // 再把秒数转为天、时、分、秒
            let d = parseInt(subTime/60/60/24); //天
            let h = parseInt(subTime/60/60%24); // 时
            h = h<10?'0'+h:h;
            hours.innerHTML= h;

            let m = parseInt(subTime/60%60);  //分
            m = m<10?'0'+m:m;
            minute.innerHTML=m;

            let s = parseInt(subTime%60);
            s = s<10?'0'+s:s;
            second.innerHTML=s;
            // return d+'天'+h+'时'+m+'分'+s+'秒';

        }
    </script>
</body>
</html>
7.1.4 常见窗口属性
  • window.innerHeight - 浏览器窗口的内高度(以像素计)

  • window.innerWidth - 浏览器窗口的内宽度(以像素计)

    Internet Explorer 8, 7, 6, 5 用以下

  • document.documentElement.clientHeight

  • document.documentElement.clientWidth

  • document.body.clientHeight

  • document.body.clientWidth

7.1.5 案例:显示(任意)浏览器宽高
<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>
71.6 其他方法
window.open(URL,name,specs,replace); // (待续)
window.close();
<button onclick="openWindow()">打开新窗口</button>
<button onclick="closeWindow()">关闭窗口</button>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
	let myWindow;
    function openWindow() {
        myWindow = window.open('', '', 'width=400,height=300');
        myWindow.document.write("<h1>这是新建窗口</h1>");
    }

    function closeWindow() {
        myWindow.close();
    }
</script>

7.2 Navigator对象

var browse = navigator.userAgent;
console.log(browse);

// 弹窗显示你的浏览器
var browse = navigator.userAgent;
if (/firefox/i.test(browse)) {
    alert("你是火狐浏览器");
} else if (/chrome/i.test(browse)) {
    alert("你是谷歌浏览器");
} else if (/msie/i.test(browse)) {
    alert("你是IE5-IE10浏览器");
} else if ("ActiveXObject" in window) {
    alert("你是IE11浏览器");
}

7.3 Location 对象

7.3.1 介绍

Location对象中封装了浏览器的地址栏的信息,如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)

console.log(location);
/*
常见属性:
herf:网页地址全路径(协议+路径);
origin:来源
protocol:协议
hostname:地址所在的主机名
host:地址所在的主机
port:端口号
pathname:路径
search:路径参数
*/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uI14KEIi-1679284523328)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663897410435.png)]

7.3.2 常用方法
history.back();  // 回退到上一个页面
history.forward();  // 前进到下一个页面 
history.go(-2);	
// 参数:1,2,-1,-2	
// 1 2 : forward到下1/2页
// -1 -2 :back到前面1/2页

7.4 Screen对象

常用属性:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-03cgXxjw-1679284523329)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663899525539.png)]

8 JavaScript进阶

8.1 异常(Exception)

8.1.1 异常概述

ES3及之后,js提供了异常处理机制,使得程序即使出现了异常仍能正常跑完程序

  • Error对象
    • 属性1: name:错误名
      • EvalError : 已在 eval() 函数中发生的错误
      • RangeError : 已发生超出数字范围的错误
      • ReferenceError : 已发生非法引用
      • SyntaxError : 已发生语法错误
      • TypeError : 已发生类型错误
      • URIError : 在 encodeURI() 中已发生的错误
    • 属性2: message :错误消息
8.1.2 异常捕获
try {
    console.log(a);// 可能发生异常的代码
    console.log("a未定义报错,这行不执行");// try 中一旦出现错误则其它语句不能执行
    
} catch (error) {
    // 发生错误执行的代码,没有错误则不执行catch
    
} finally {
    // 无论是否出错都会执行的代码,理解为收尾工作
}
8.1.3 抛出异常

在大部分的代码执行过程中,都是出现错误的时候,由浏览器(JavaScript引擎)抛出异常,然后程序或者停止执行或被try…catch 捕获。

然而有时候我们在检测到一些不合理的情况发生的时候也可以主动抛出错误,请使用 throw 关键字抛出来主动抛出异常。

function foo(num) {
    if (typeof num == "number") {
        return num * num;
    } else {
        throw new TypeError("您输入的是一个非法数字!")
    }
}

抛出自定义异常

function MyError(message) {
    this.message = "注意:这是自定义的错误"
    this.name = "自定义错误";
}
//自定义错误类型,只需继承任何一个自定义错误类型都可以,一般直接继承Error
 MyError.prototype = new Error();

try {
    throw new MyError("注意:这是自定义错误类型")
} catch (error) {
    console.log(error.message)
}

8.2 Json

8.2.1 json概述

它是一种存储和交换数据的语法。

当数据在浏览器与服务器之间进行交换时,这些数据只能是文本,JSON 属于文本并且我们能够把任何 JavaScript 对象转换为 JSON,然后将 JSON 发送到服务器。我们也能把从服务器接收到的任何 JSON 转换为 JavaScript 对象。以这样的方式,我们能够把数据作为 JavaScript 对象来处理,无需复杂的解析和转译。

8.2.2 json语法
  • 在json中,每一个数据项,都是由一个键值对

  • 键必须是字符串,用双引号包围

  • 值必须是:

    • String
    • Number
    • Object
    • 数组
    • true/false
    • null
  • 值不能是函数,日期,undefined

  • 值为数字时必须是整数或者浮点数

  • 值为对象时,对象必须遵守json对象的规则

// 创建一个json对象
var animal = {
    "type":"tiger",
    "name":"泰哥",
    "age":"18"
}
console.log(animal)
8.2.3 json字符串与JS对象相互转换

JSON.parse(str):json->js

let jsonStr = '{"name":"liang","age":18}';
console.log(jsonStr);
let obj = JSON.parse(jsonStr);
console.log(obj);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xi5NKZMJ-1679284523329)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663985460799.png)]

JSON.stringify(obj):js->json

var obj = {name: "liang", age: 18};
var jsonStr = JSON.stringify(obj);
console.log(jsonStr);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MFGceqsj-1679284523330)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663985766755.png)]

8.3 AJAX

  • 传统web交互

用户发出http请求到服务器,服务器将资源响应到浏览器,且返回的是一个新页面

缺点:即使一个小的数据变换都要返回整个新页面,浪费时间和带宽,响应时间也会相对慢很多,用户体验感差。

  • AJAX技术

ajax技术可以让网页异步更新,在不加载整个网页的前提下,更新用户需要的数据

技术限制:请求加载的网页与XML配置文件必须在同一台服务器上

8.3.1 XMLHttpRequest对象

ajax的核心对象,所有浏览器兼容

  • 创建XMLHttpRequest
let aj_XHR = new XMLHttpRequest();

// ie5和ie6
let aj_XHR = new ActiveXObject("Microsoft.XMLHTTP");
8.3.2 XMLHttpRequest常用对象属性
  • onreadystatechange: 定义当 readyState 属性发生变化时被调用的函数
  • readyState : 保存 XMLHttpRequest 的状态
  • 0:请求为初始化
  • 1:服务器连接已建立
  • 2:收到请求
  • 3:处理请求
  • 4:完成请求,响应就绪
  • responseText : 以字符串返回响应数据
  • responseXML : 以 XML 数据返回响应数据
  • status : 返回请求的状态号
  • 200:“OK”
  • 403:“ Forbidden ”
  • 404:“ Not Found ”
  • ········
  • Http 消息参考手册
  • statusText : 返回状态文本(比如 “OK” 或 “Not Found”)
8.3.3 XMLHttpRequest常用对象方法
  • new XMLHttpRequest():创建新的XHR对象
  • abort():取消当前请求
  • getAllResponseHeaders() :返回头部信息
  • getResponseHeader() :返回特定头信息
  • open(method,url,async,[user],[password]):文件
    • method: GET/POST
    • url: 请求的路径
    • async: true(异步)/false(同步)
    • user: 可选
    • password: 可选
  • send():发送GET请求
  • send(string):发送POST请求
  • setRequestHeader() : 向要发送的报头添加标签/值对
8.3.4 发送GET请求

项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLHmOrYu-1679284523331)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663988965680.png)]

animal.json

[
  {"type":"monkey","age": 18},
  {"type":"tiger","age": 19},
  {"type":"lion","age": 20}
]
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>

</head>
<body>
<script>
    <!--    1、创建ajax-->
    let ajax = new XMLHttpRequest();
//  2.open('method','url'):请求的方法和路径
    ajax.open("get","./animal.json")
//  3.发送请求
    ajax.send();
//  4.注册事件
    ajax.onreadystatechange = function (){
        if(ajax.readyState===4 && ajax.status===200){
            console.log(ajax.getAllResponseHeaders());
            console.log(ajax.responseText);
            console.log(ajax.responseURL);
        }
    }
</script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pDi0ojn1-1679284523332)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663988864586.png)]

8.3.5 发送POST请求
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
// 1.创建ajax-->
let ajax = new XMLHttpRequest();
//2. 打开文件,设置post参数
ajax.open("post","./animal.json");
//3.发送请求
ajax.send();
// 4.注册事件
ajax.onreadystatechange = function (){
    if(ajax.readyState===4&&ajax.status===200){
        console.log(ajax.responseText);
    }
}
</script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9mx2t8DZ-1679284523333)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663989483354.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4UUwOWMB-1679284523334)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1663989539735.png)]

8.3.6 请求整合
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
//  1.创建XMLHttpRequest()对象
//  2.open("method","path"),打开资源文件
//  3.send()发送请求
//  4.处理程序
    let ajax = {
        // 传入一个路径和操作方法
        get:function (url,fn) {
            let xhr = new XMLHttpRequest();
            xhr.open("get",url,true);
            xhr.send();
            xhr.onreadystatechange = function (){
                if(xhr.readyState===4&&xhr.status===200){
                    fn.call(this,xhr.responseText);
                }
            }
        },
        post: function (url, data, fn) {
            let xhr = new XMLHttpRequest();
            xhr.open("POST", url, true);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)) {
                    fn.call(this, xhr.responseText);
                }
            };
            xhr.send(data);
        }
    };
// 演示GET请求
ajax.get("animal.json", function (response) {
    console.log(response);
});

// 演示POST请求
ajax.post("animal.json", "", function (response) {
    console.log(response);
});

</script>
</body>
</html>

8.4 cookie

8.4.1 cookie

cookie就是用户浏览器中的一些数据,用来解决----关闭与服务区的连接后,服务器端不会记录用户的数据----的问题

8.4.2 cookie增查删改
// 增
document.cookie = "username=liang";
// 添加过期时间
document.cookie = "username=zhangsan; expires=Thu, 18 Dec 2022 12:00:00 GMT";

// 查
document.cookie="username=liang";
let cookies = document.cookie;
console.log(cookies);

// 改
document.cookie = "username=liang";
document.cookie = "username=li";
let cookies = document.cookie;
console.log(cookies);

//删 :将cookie的过期时间设置为以前的时间即可
document.cookie = "username=zhangsan";
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
let cookies = document.cookie;
console.log(cookies);
8.4.3 设置cookie值函数
/**
 * Cookie值设置函数
 * @param cname     cookie名称
 * @param cvalue    cookie值
 * @param exdays    过期天数
 */
function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
    var expires = "expires=" + d.toGMTString();
    document.cookie = cname + "=" + cvalue + "; " + expires;
}
8.4.4 获取cookie值函数
/**
 * Cookie值获取函数
 * @param cname     cookie名称
 * @returns {string}
 */
function getCookie(cname) {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i].trim();
        if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
    }
    return "";
}

8.5 WebStorage(存储)

本地存储特点:

  • 数据存在浏览器中
  • 读写方便,数据不会丢失
  • 容量可观:sessionStorage可存5M,localStorage可存20M;
  • 只能存字符串,对象需json格式化后存储
8.5.1 sessionStorage

生命周期:直至关闭浏览器,刷新页面也不会丢失

数据共享:同一个页面里共享

存储方式:key:value

主要方法:

  • sessionStorage.setItem(‘key’,value):存储数据

  • sessionStorage.getItem(‘key’):获取数据

  • sessionStorage.removeItem(‘key’):删除数据

  • sessionStorage.clear():删除所有数据

8.5.2 localStorage

本地存储

生命周期:永久

数据共享:多窗口,只要同个浏览器

存储方式:key:value

主要方法:

  • localStorage.setItem(‘key’,value):存储数据

  • localStorage.getItem(‘key’):获取数据

  • localStorage.removeItem(‘key’):删除数据

  • localStorage.clear():删除所有数据

8.5.3 案例:记住用户名
 <input type="text" id="username">
    <input type="checkbox" id="remember-me">记住我

    <script>
        let name = document.querySelector('#username');
        let re = document.querySelector('#remember-me');
        if(localStorage.getItem('name')){
            name.value = localStorage.getItem('name');
            re.checked = true;
        }
        re.addEventListener('change',function(){
            if(this.checked){
                localStorage.setItem('name',name.value);
            }
            else{
                localStorage.removeItem('name');
            }
        })
        
    </script>

8.6 闭包()

8.6.1 闭包引入

需求信息:点击某个按钮,提示"点击的是第n个按钮"

var btns = document.getElementsByTagName('button');

// 利用闭包延长局部变量的生命周期
for (var i = 0, length = btns.length; i < length; i++) {
    (function (j) {
        var btn = btns[j];
        btn.onclick = function () {
            alert('第' + (j + 1) + '个');
        }
    })(i);
}
8.6.2 闭包概述
  • 如何产生闭包?

当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包

  • 什么才是闭包?

理解一:闭包是嵌套的内部函数(绝大部分人认为)
理解二:包含被引用变量(函数)的对象(极少部分人认为)

  • 闭包的作用?

它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中

8.6.3 闭包再理解

不同的函数作用域不能互相访问对方的变量,闭包的引入就是解决这一需求的。

定义:闭包是指有权访问另一个函数作用域的变量的函数

作用:

  • 访问另一个函数作用域的变量
  • 让这些变量保存在内存中,不会随着函数的结束而销毁

闭包3个特性:

  • 嵌套函数
  • 函数内部可以引用函数外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收
	function a1(){
        let age1 = 18;
        function a2(){
            let age2=20;
            console.log("age1:"+--age1);
            console.log("age2:"+(++age2));
        }
        return a2;
    }
    let b = a1();
    b();
    console.log("=========");
    b();
    console.log("=========");
    b();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZwK7L0j8-1679284523335)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664003845358.png)]

上图所示,变量age1是父级作用域a1()的变量,被一个作为返回值的函数a2()使用,此时,age1和a2()形成闭包,age1不会被销毁一直存在内存中,age2每调用一次重新创建一次,销毁一次。

8.7 js执行机制

8.7.1 js的单线程和同步异步

因为js是处理与用户交互的一门脚本语言,因此决定了操作DOM不可以同时进行异步操作,同一时间内同一DOM元素要么删除,要么修改、要么增加。

js单线程的特性意味着,所有的任务需要排队,如果js执行时间太长会导致页面渲染不连贯、阻塞等问题,比如下面的例子

// 打印完了1,等待2s后才打印3,最后打印2,非常耗时
// js会有机制,保证了优先处理不耗时的任务
// 所以实际输出1、2、3
console.log(1);
setTimeout(()=>console.log(3),2000);
console.log(2);

上述问题的解决方法就是,利用多核CPU的计算能力,H5的Web Worker标准允许js脚本创建多个线程,所以js才有了同步和异步

同步:任务按顺序依次执行

异步:任务并发或并行执行

8.7.2 同步任务和异步任务的执行过程
// 思考当定时器时间为0的时候,下列程序执行顺序
console.log(1);
setTimeout(()=>console.log(3),0);
console.log(2);
// 实际上仍然是1、2、3

实际上仍然是1、2、3,js的同步任务和异步任务的执行过程有先后顺序

同步任务:在主线程上执行,在

**异步任务:**分三种类型,相关的回调函数会添加到任务队列中

  • 普通事件:click、resize等
  • 资源加载:如load、error
  • 定时器:setTimeout、setInterval

9 PC端网页特效

9.1 元素偏移量offset系列

  • 获得带定位的父元素的位置
  • 获得元素自身的大小

注意:获得的值不带单位

属性描述
offsetParent返回(有定位的)父元素,父元素可以是body
offsetTop元素顶部距离(有定位的)父元素的距离
offsetLeft元素左边距离(有定位的)父元素边框的距离
offsetWidth元素宽度:包括边框、padding、内容
offsetHeight元素高度:包括边框、padding、内容
offset和style的区别:
  • offset可以获取任意样式表的值,style只能获取行内样式
  • offset获取的值为数字类型,没有单位,style的值有单位,是字符串
  • offsetWidth包含padding+border+width,style.width只包含width
  • offset只读,style可读可写
  • 当我们需要获取元素的大小,offset更合适
<div style="width: 200px;padding: 20px;"></div>
    <script>
        let div = document.querySelector('div');
        console.log(div.offsetWidth);
        console.log(div.style.width);
    </script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NYEsHSjQ-1679284523336)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1666456280689.png)]

mouseover和mouseenter的区别:
  • mouseenter和mouseleave不会冒泡

9.2 元素可视区client系列

属性描述
clientTop元素上边框的大小
clientLeft元素左边框的大小
clientWidth元素宽度:包含padding和内容(无单位)
clientHeight元素高度:包含padding和内容(无单位)

9.3 元素滚动scroll系列

属性描述
scrollTop被卷去的上侧距离
scrollLeft被卷去的左侧距离
scrollWidth返回自身实际宽度,不含边框
scrollHeight返回自身实际宽度,不含边框

9.4 动画函数封装

常见网页特效

JQuery

1 JQuery

1.1 JQuery概述

  • 轻量级JavaScript库,封装了常用的js功能代码,

  • 优化了事件处理,DOM操作,提高开发速度

  • 兼容性强

  • 链式编程

  • 支持扩展

  • 免费开源

1.2 下载jquery

https://jquery.com/download/

生产版:体积小

开发版:体积稍大,功能注释清晰

2 JQuery使用

  • 引入jq
<script src="./js/jquery.min.js"></script>
  • 语法:$(‘selector’).action();

$符开头

selector:需要处理的元素

action():处理函数

就像原生js的顶级对象是window一样,$是jquery的顶级对象

2.1 JQ入口函数

// 方式一:
$(function(){
    // 代码
});
// 方式二:
$(document).ready(function(){
    // 代码
});

2.2 jQuery对象和DOM对象

jq对象利用$对DOM对象包装后的对象(存储形式为伪数组

<script>
        // DOM对象
        let div = document.querySelector('.box');
        console.dir(div);

        // $('.box')一整个就是jq对象
        $('.box');
        console.dir($('.box'));

    </script>

**注意:**jq对象只能使用jQuery封装的方法,原生js的DOM对象也不能使用jQuery方法

2.3 jQuery对象与DOM对象转换

因为原生js对象有很多jQuery库中没有的方法,所以有转换的必要性

  • DOM对象转为jQuery对象:$(DOM对象)

  • jQuery对象转换DOM对象:$(‘selector’)[index] ;index:索引

3 jQuery常用API

3.1 jQuery选择器

3.1.1 jQuery基础选择器

$(‘selector’);selector与CSS选择器一样,写入相关的选择器名字即可

名称用法描述
通配符选择器$(‘*’)匹配所有元素
id选择器$(‘#id’)获取指定id元素
class选择器$(‘.class’)获取同一类选择器
标签选择器$(‘div’)获取某种标签元素
并集选择器$(‘div,li,p’)获取多个元素
交集选择器$(li.box)交集元素
后代/亲儿子选择器 ( ′ u l l i ′ ) / ('ul li')/ (ulli)/(‘div>p’)
3.1.2 隐式迭代

jQuery匹配到的元素,遍历内部DOM元素(伪数组形式存储)的过程就是隐式迭代

3.1.3 筛选选择器
语法用法描述
:first$(‘li:first’)第一个li
:last$(‘li:last’)最后一个li
:eq(index)$(‘li:eq(index)’)获取一组li中的索引为index的li
:odd$(‘li:odd’)获取一组li中的索引为奇数的li
:even$(‘li:even’)获取一组li中的索引为偶数的li
 $(function(){
            $('ul li:first').css('background','pink');
            $('ul li:last').css('color','red');
            $('ul li:eq(3)').css('color','yellow');
            $('ol>li:odd').css('color','blue');
            $('ol>li:even').css('color','green');

        });
3.1.4 筛选方法
语法用法描述
parent()$(‘li’).parent()获取父级元素
children(‘selector’)$(‘ul’).children(‘li’)相当于$(‘ul>li’)亲儿子
find()$(‘ul’).find(‘li’)$(‘ul li’)
sublings(‘selector’)$(‘.first’).sublings(‘li’)获取兄弟节点
nextAll([expr])$(‘.first’).nextAll()当前元素之后所有同辈节点
prevtAll([expr])$(‘.first’).prevtAll()当前元素之前所有同辈节点
hasClass(‘class’)$(‘div’).hacClass(‘box’)是否含有某个类,是为true
eq(index)$(‘li’).eq(2)$(‘li:eq(2)’)

3.2 下拉菜单


    <style>
        li {
            list-style: none;
        }
        a {
            text-decoration: none;
        }
        span {
            display: block;
            height: 50px;
            width: 100px;
            line-height: 50px;
            text-align: center;
            background-color: aqua;
        }
        .list {
            display: none;
            padding-inline-start:0px
        }
        .list li {
            height: 50px;
            width: 98px;
            border: 1px solid #ffe793;
            line-height: 50px;
            text-align: center;
        }

    </style>

<body>

   
    <ul class="table" style="width:100px;height: 200px;">
        <span class="">链接V</span>
        <ul class="list">
            <li>
                <a href="https://www.baidu.com" target="_blank">百度一下</a>
            </li>
            <li>
                <a href="https://www.weibo.com" target="_blank">微博</a>
            </li>
            <li>
                <a href="">淘宝</a>
            </li>
        </ul>
        
    </ul>

    <script>
        // 鼠标经过--链接--,显示ul链接表
        $(function(){

            $('.table').children('span').mouseover(function(){
                // $('.table>ul').css('display','block');
                $('.table>ul').show();

            });

            $('.table').mouseleave(function(){
                $('.table>ul').css('display','none')
            });

        })
    </script>
</body>

3.3 jQuery的排他思想

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script src="./js/jquery.js"></script>
</head>
<body>
    
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>

    <script>
        // 隐式迭代、所有的按钮绑定点击事件
        $('button').click(function(){
            // 当前元素点击后变背景颜色
            $(this).css('background','pink');
            // 当前元素的兄弟元素去掉背景颜色
            $(this).siblings('button').css('background','')
        })
    </script>

</body>
</html>
tab栏图片切换案例
<style>
        *{
            margin: 0;padding: 0;
        }
        li {
            list-style: none;
        }
        .box {
            width: 600px;height: 360px;background-color: aqua;
        }
        ul img{
            height: 360px; width: 500px;
        }

        .box ul{
            float: left;
        }
        .imgname li {
            height: 120px;line-height: 120px; border: 1px solid black;
        }
    </style>
    
    <div class="box">
        <ul class="imgname">
            <li>赵云</li>
            <li>ys</li>
            <li>windows</li>
        </ul>
        <ul class="img">
            <li style="position: absolute;">
                <img src="./images/1.jpg" >
            </li>
            <li style="position: absolute;">
                <img src="./images/2.jpg" >
            </li>
            <li style="position: absolute;">
                <img src="./images/5.jpg" >
            </li>
        </ul>
    </div>
    

    <script>
        $(function(){
            $('.imgname li').mouseover(function(){
                let index = $(this).index();
                // console.log(index);
                $('.img li').eq(index).show();
                $('.img li').eq(index).siblings().hide()
            })
        })
        
    </script>

3.4

ES新特性

ES(EcmaScript)是脚本语言的规范

学习的必要性:

语法简介,功能丰富

框架开发应用广泛

前端开发的要求提高

1 ES6

1.1 let、const关键字

let:

  • 不允许重复声明
  • 块儿级作用域
  • 不存在变量提升
  • 不影响作用域链

const:

  • 不允许重复声明
  • 块儿级作用域
  • 声明必须赋初始值
  • 值不允许修改
  • 标识符一般为大写

一般约定 let声明变量,const声明对象和常量

1.2 解构赋值

//数组的解构赋值
const arr = ["张学友", "刘德华", "黎明", "郭富城"];
let [zhang, liu, li, guo] = arr;
console.log(zhang);
console.log(liu);
console.log(li);
console.log(guo);

//对象的解构赋值
const lin = {
    name: "林志颖",
    tags: ["车手", "歌手", "小旋风", "演员"]
};
let {name, tags} = lin;
console.log(name);
console.log(tags);

//复杂对象的解构赋值
let wangfei = {
    name: "王菲",
    age: 18,
    songs: ["红豆", "流年", "暧昧"],
    history: [
        {name: "窦唯"},
        {name: "李亚鹏"},
        {name: "谢霆锋"}
    ]
};
let {name, age, songs: [one, two, three], history: [first, second, third]} = wangfei;
console.log(name);
console.log(age);
console.log(one);
console.log(two);
console.log(three);
console.log(first);
console.log(second);
console.log(third);

1.3 模板字符串

增强型字符串,用飘引号``包围

let str =
`<ul>
   <li>青龙</li>
   <li>白虎</li>
   <li>朱雀</li>
   <li>玄武</li>
/ul>`;
console.log(str);
1664005517160

1.4 字符串拼接

支持字符串用${var}拼接,前提是拼接者用飘引号

let idol = '刘德华';
let text = `我的偶像是${idol}`;
console.log(text);

1.5 对象简化写法

let name = "张三";
let age = 18;
let speak = function () {
    console.log("我叫"+this.name);
};

//属性和方法简写
let person = {
    name,
    age,
    speak
};
console.log(person.name);
console.log(person.age);
person.speak();

1.6 箭头函数

// 传统写法
let fn = function(arg1, arg2,···){
    // do something
}
// 箭头函数
let fn = (arg1, arg2, ···) => {
    // do something
}
let v = (arg1, arg2,···)=>{};
// 当形参只有一个时,小括号可以省略
let v = arg1 =>{};
// 当语句只有一条时,花括号可以省略
let v = (arg1, arg2,···)=>return arg1;

this 指向声明时所在作用域中 this 的值

1.7 rest参数

// 作用与 arguments 类似
function add(...args) {
    console.log(args);
}
add(1, 2, 3, 4, 5);

// rest 参数必须是最后一个形参
function minus(a, b, ...args) {
    console.log(a, b, args);
}
minus(100, 1, 2, 3, 4, 5, 19);

1.8、spread 扩展运算符

扩展运算符(spread)也是三个点(…),它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

// 展开数组
let tfboys = ["德玛西亚之力", "德玛西亚之翼", "德玛西亚皇子"];
function fn() {
    console.log(arguments);
}
fn(...tfboys);

// 展开对象
let skillOne = {
    q: "致命打击"
};
let skillTwo = {
    w: "勇气"
};
let skillThree = {
    e: "审判"
};
let skillFour = {
    r: "德玛西亚正义"
};
let gailun = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};
console.log(gailun);

1.9 Symbol类型(待续)

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,它是 JavaScript 语言的第七种数据类型

//创建 Symbol
    let s1 = Symbol();
    console.log(s1);
    console.log(typeof s1);
    console.log("==========");
    //添加标识的 Symbol
    let s2 = Symbol("张三");
    let s2_2 = Symbol("张三");
    console.log(s2);
    console.log(s2_2);
    console.log(s2 === s2_2);
    console.log("==========");
    //使用 Symbol for 定义
    let s3 = Symbol.for("张三");
    let s3_2 = Symbol.for("张三");
    console.log(s3);
    console.log(s3_2);
    console.log(s3 === s3_2);

    //在方法中使用 Symbol
    let game = {
        name: "狼人杀",
        [Symbol('say')]: function () {
            console.log("我可以发言")
        },
        [Symbol('zibao')]: function () {
            console.log('我可以自爆');
        }
    };
    console.log(game);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQ6gz8Tx-1679284523337)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664007542536.png)]

1.10 迭代器( Iterator )

  • Array
  • Arguments
  • Set
  • Map
  • String
  • TypedArray
  • NodeList

案例演示:自定义遍历数据

//声明一个对象
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);
}

1.11 生成器(待续)

1.12 Promise

Promise 是 ES6 引入的异步编程的新解决方案,语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

1.12.1 Promise优势
  • 指定回调函数的方式更加灵活
    • 旧的:必须在启动异步任务前启动
    • promise:启动异步任务=》返回promise对象=》给promise对象绑定回调函数
  • 支持链式调用,解决回调地狱问题,便于阅读和异常处理

**Promise语法:**参数是一个函数,该函数有俩形参(

resolve(解决):异步任务成功 的时候

reject(拒绝):异步任务失败的时候

)

1.12.2 体验案例

抽奖,30%中奖率

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>点击抽奖</button>
    <button>Promise点击抽奖</button>

    <script>
        // 生成m-n的随机数
        function rand(m,n){
            return Math.ceil(Math.random()*(n-m+1))+m-1;
        };
        // 点击一秒后,30%概率中奖
        let btns = document.querySelectorAll('button');
        btns[0].addEventListener('click',function(){
            setTimeout(()=>{
                let n = rand(1,100);
                if(n<=30)alert('中奖啦'+'---'+n)
                else alert('再接再厉'+'---'+n)
            },500);
        });

        // Promise形式
        // Promise(fun),fun(resolve,reject)
        // resolve:解决(异步任务成功时调用),将Promise对象的状态设为成功
        //  reject:拒绝(异步任务失败时调用),将Promise对象的状态设为失败
        btns[1].addEventListener('click',function(){
            
            let p = new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    let n = rand(1,100);
                    if(n<=30) resolve(n);
                    else reject(n);
                },500)
            });
            btns[1].disabled=true
            // 调用p.then方法,两个函数参数,
            // 第一个参数成功时回调,value,成功的值
            // 第二个失败时回调,reason,错误的理由
            p.then((value)=>{
                alert('Promise:中奖啦'+'---'+value);
                btns[1].disabled = false
            },(reason)=>{
                alert('promise:再接再厉'+'---'+reason);
                btns[1].disabled = false
            })
        })
        
    </script>
</body>
</html>
1.12.3 Promise封装ajax

1 使用node创建一个服务器(app.js)

const express = require('express');
const app = express();
// 路由规则
app.get('/t',(req,res)=>{
    // 允许跨域请求
    res.setHeader('Access-Control-Allow-Origin','*')
    // 允许自定义请求头信息
    res.setHeader('Access-Control-Allow-Headers','*');
    let = data = {
        name:'liang',
        age:18
    }
    let str = JSON.stringify(data);
    // 响应数据
    res.send(str)
})

// 启动服务器
app.listen(9000,()=>{
    console.log('espress is running at http://localhost:9000/');
})

客户端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <button>点击发送ajax</button>
    <button>Promise点击发送ajax</button>

    <script>
        let btns = document.querySelectorAll('button');
        btns[0].onclick = function(){
            let x = new XMLHttpRequest();
            x.responseType = 'json'
            x.open('GET','http://localhost:9000/t');
            x.send();
            x.onreadystatechange = function(){
                if(x.readyState===4){
                    if(x.status>=200&&x.status<300){
                        console.log(x.response);
                    }else console.log(x.status);
                }
            }
        }

        btns[1].addEventListener('click',function(){
            const p = new Promise((resolve,reject)=>{
                let x = new XMLHttpRequest();
                x.responseType = 'json'
                x.open('GET','http://localhost:9000/t');
                x.send();
                x.onreadystatechange = function(){
                    if(x.readyState===4){
                        if(x.status>=200&&x.status<300){
                            resolve(x.response);
                        }else reject(x.status);
                    }
                }
            });
            p.then((value)=>{
                console.log(value);
            },(reason)=>{
                console.warn(reason);
            })
            
        })
        
    </script>

</body>
</html>
Promise封装ajax请求
function sendAjax(method,url){
            return new Promise((resolve,reject)=>{
                const xhr = new XMLHttpRequest();
                xhr.open(method,url);
                xhr.send();
                xhr.onreadystatechange = function(){
                    if(xhr.readyState===4){
                        if(xhr.status>=200&&xhr.status<300)resolve(xhr.response);
                        else reject(xhr.status);
                    }
                }
                
            })
        }
1.12.4 Promise.resolve()方法

resolve是Promise的静态函数,resolve(value)返回一个成功或失败的Promise对象,

value值绝对Promise的状态

  • value为基本数据类型和非Promise实例,返回成功的Promise对象
  • value为一个Promise实例,实例的状态决定该Promise的状态
1.12.5 Promise.reject()方法

resolve是Promise的静态对象,返回一个失败的Promise对象

1.12.6 Promise.all(promises)方法

all是Promise的静态对象,

参数promises:包含n个Promise对象的数组

返回值:返回一个Promise对象,只有n个Promise对象都是成功状态,则返回的对象才成功,失败的结果是参数里失败的Promise对象的结果

1.12.7 Promise.race(promises)方法

race是Promise的静态对象,

参数promises:包含n个Promise对象的数组

返回值:返回一个Promise对象,由参数里第一个完成的Promise对象的结果决定该Promise对象的状态

1.12.8 Promise常见疑问?
状态改变的方式
  • resolve
  • reject
  • 抛出错误:throw
Promise能否执行多个回调(then)?

成功时,成功的回调都会执行

改变Promise状态和指定回调函数先后 ?

不确定

1.12.9 自定义实现Promise
  • 1 创建Promise.js,创建Promise构造函数,传入一个函数参数excutor
function Promise(excutor){}

// 添加then方法,两个形参,成功、失败
Promise.prototype.then = function(ok,err){
}
  • 2 自定义封装resolve、reject构建
// 1 构造函数
function Promise(excutor){

    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){

    };
    function reject(data){

    }

    2 // 同步调用
    excutor(resolve,reject);
}

// 1 添加then方法
Promise.prototype.then = function(ok,err){

}
  • 3 自定义封装resolve、reject实现
// 1 构造函数
function Promise(excutor){

    // 3 添加对象状态属性
    this.PromiseState = 'pending';

    // 3 添加对象结果属性
    this.PromiseResult = null;

    // 3 保存实例对象this的值
    const self = this;
    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'fulfilled';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    };
    // 2
    function reject(data){
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'rejected';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    }

    2 // 同步调用
    excutor(resolve,reject);
}

// 1 添加then方法
Promise.prototype.then = function(ok,err){

}
  • 4 自定义封装- throw抛出异常
    // 4 设置 try -- catch
    try {
        2 // 同步调用
        excutor(resolve,reject);
    } catch (err) {
        // 修改Promise状态为’失败‘;
        reject(err);
    }
  • 5 Promise的状态只能修改一次
// 1 构造函数
function Promise(excutor){

    // 3 添加对象状态属性
    this.PromiseState = 'pending';

    // 3 添加对象结果属性
    this.PromiseResult = null;

    // 3 保存实例对象this的值
    const self = this;
    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'fulfilled';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    };
    // 2
    function reject(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'rejected';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    };
   
    // 4 设置 try -- catch
    try {
        2 // 同步调用
        excutor(resolve,reject);
    } catch (err) {
        // 修改Promise状态为’失败‘;
        reject(err);
    }


}

// 1 添加then方法
Promise.prototype.then = function(ok,err){

}
  • 6 then方法执行回调
// 1 构造函数
function Promise(excutor){

    // 3 添加对象状态属性
    this.PromiseState = 'pending';

    // 3 添加对象结果属性
    this.PromiseResult = null;

    // 3 保存实例对象this的值
    const self = this;
    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'fulfilled';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    };
    // 2
    function reject(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'rejected';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data
    };
   
    // 4 设置 try -- catch
    try {
        2 // 同步调用
        excutor(resolve,reject);
    } catch (err) {
        // 修改Promise状态为’失败‘;
        reject(err);
    }


}

// 1 添加then方法
Promise.prototype.then = function(ok,err){
    // 6 调用回调函数,关键:在then方法获取Promise的属性
    // this由Promise实例调用,this指向Promise实例
    if(this.PromiseState==='fulfilled'){ 
        // 6 实际调用的时候有形参value,
        // 6这里应该传入实参value,也就是Promise的结果
        ok(this.PromiseResult);
    }
    // 6
    if(this.PromiseState==='rejected'){
        // 6
        err(this.PromiseResult);
    }

}
<script src="./Promise.js"></script>
<script>
        let p = new Promise((resolve,reject)=>{
            resolve('ok');
            reject('err');
            // throw 'err'
        });

        console.log(p);

        p.then(value=>{
            console.log(value);
        },reason=>{
            console.log(reason);
        })
    </script>
  • 7 异步任务回调的执行
<script src="./Promise.js"></script>
<script>
        let p = new Promise((resolve,reject)=>{
            // 7异步任务,因为延时,Promise还处于,初始化阶段(pending),既不成功也不失败
            // 7如果Promise还是处于第六步,then方法无法获取状态,不执行
            setTimeout(()=>{
                resolve('ok');
                reject('err');
                // throw 'err'
            },1000)
        });

        p.then(value=>{
            console.log(value);
        },reason=>{
            console.log(reason);
        })
    </script>
// 1 构造函数
function Promise(excutor){

    // 3 添加对象状态属性
    this.PromiseState = 'pending';

    // 3 添加对象结果属性
    this.PromiseResult = null;

    // 3 保存实例对象this的值
    const self = this;

    // 为实例声明一个对象属性保存回调函数
    this.callback= {};


    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'fulfilled';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data;

        // 7调用成功的回调函数,怎么调?
        if(self.callback.ok){
            self.callback.ok(data); // 7
        }
    };
    // 2
    function reject(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'rejected';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data;

        // 7调用失败的回调函数,怎么调?
        if(self.callback.err){
            self.callback.err(data); // 7
        }
    };
   
    // 4 设置 try -- catch
    try {
        2 // 同步调用
        excutor(resolve,reject);
    } catch (err) {
        // 4 修改Promise状态为’失败‘;
        reject(err);
    }


}

// 1 添加then方法
Promise.prototype.then = function(ok,err){
    // 6 调用回调函数,关键:在then方法获取Promise的属性
    // this由Promise实例调用,this指向Promise实例
    if(this.PromiseState==='fulfilled'){ 
        // 6 实际调用的时候有形参value,
        // 6这里应该传入实参value,也就是Promise的结果
        ok(this.PromiseResult);
    }

    // 6
    if(this.PromiseState==='rejected'){
        // 6
        err(this.PromiseResult);
    }

    // 7判断PromiseState是不是pending,只有改变了才能执行then
    if(this.PromiseState==='pending'){
        // 7保存回调函数
        this.callback = {
            ok, //7
            err //7

        }
    }



}
  • 8 指定多个回调的实现
<script>
        let p = new Promise((resolve,reject)=>{
            // 7异步任务,因为延时,Promise还处于,初始化阶段(pending),既不成功也不失败
            // 7如果Promise还是处于第六步,then方法无法获取状态,不执行
            setTimeout(()=>{
                // resolve('ok');
                reject('err');
                // throw 'err'
            },1000)
        });

        p.then(value=>{
            console.log(value);
        },reason=>{
            console.log(reason);
        });

        // 8 第二个回调执行,覆盖了第一个
        p.then(value=>{
            alert(value);
        },reason=>{
            alert(reason);
        });
        
        console.log(p);
    </script>
// 1 构造函数
function Promise(excutor){

    // 3 添加对象状态属性
    this.PromiseState = 'pending';

    // 3 添加对象结果属性
    this.PromiseResult = null;

    // 3 保存实例对象this的值
    const self = this;

    // 7为实例声明一个对象属性保存回调函数
    // 7 this.callback= {};

    // 8 将保存回调的属性设置为数组
    this.callbacks=[];


    // 2 声明成功和失败的处理方法,data:Promise状态的数据
    function resolve(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'fulfilled';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data;

        // 7调用成功的回调函数,怎么调?
        // if(self.callback.ok){
        //     self.callback.ok(data); // 7
        // }

        // 8 调用成功的回调函数,怎么调? 循环遍历callbacks里的回调
        self.callbacks.forEach(i=>{
            i.ok(data);  // 8
        })
    };
    // 2
    function reject(data){
        // 5 判断状态是否已被修改
        if(self.PromiseState !=='pending') return;
        
        // 3 修改对象的状态,promiseState
        self.PromiseState = 'rejected';
        // 3设置对象结果 promiseResult
        self.PromiseResult = data;

        // 7调用失败的回调函数,怎么调?
        // if(self.callback.err){
        //     self.callback.err(data); // 7
        // }

        // 8 调用失败的回调函数,怎么调? 循环遍历callbacks里的回调
        self.callbacks.forEach(i=>{
            i.err(data);//8
        })
    };
   
    // 4 设置 try -- catch
    try {
        2 // 同步调用
        excutor(resolve,reject);
    } catch (err) {
        // 4 修改Promise状态为’失败‘;
        reject(err);
    }


}

// 1 添加then方法
Promise.prototype.then = function(ok,err){
    // 6 调用回调函数,关键:在then方法获取Promise的属性
    // this由Promise实例调用,this指向Promise实例
    if(this.PromiseState==='fulfilled'){ 
        // 6 实际调用的时候有形参value,
        // 6这里应该传入实参value,也就是Promise的结果
        ok(this.PromiseResult);
    }

    // 6
    if(this.PromiseState==='rejected'){
        // 6
        err(this.PromiseResult);
    }

    // 7判断PromiseState是不是pending,只有改变了才能执行then
    if(this.PromiseState==='pending'){
        // 7保存回调函数
        // this.callback = {
        //     ok, //7
        //     err //7
        // };
        
        // 8 采用push,将新的回调压入数组
        this.callbacks.push({
            ok, //8
            err, //8
        })
    }
}
  • 9 同步修改状态then方法结果返回
1.12.10 async函数
  • async函数的返回值为一个Promise对象
  • Promise对象的结果由async函数的返回值决定
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        async function main(){
            // 如果返回值是一个非Promise类型的数据,
            // 返回的Promise对象状态为成功
            // return '520';

            // 如果返回值是一个Promise对象,
            // 返回的Promise对象状态由该Promise对象决定
            // return new Promise((resolve,reject)=>{
            //     // resolve('ok');
            //     reject('err');
            // });

            // 抛出异常,返回的Promise为失败
            throw 'err'


        };
        let res = main();
        console.log(res);
    </script>
</body>
</html>
1.12.11 await表达式
  • await表达式右侧一般为一个Promise对象(也可以是其他值)
  • 如果表达式为Promise对象,返回值是Promise的结果
  • 如果表达式是其他值,直接返回这个值
  • await表达式必须写在async函数中(async可以没有await)
  • 如果await的Promise对象失败了,就会抛出异常,需要try–catch
 <script>
        async function main(){
            
            // await右侧为成功的Promise 
            console.log(await new Promise((resolve,reject)=>resolve('ok')));

            // await 右侧为其他值
            console.log(await 520);

            // 如果Promise失败
            try {
                console.log(await new Promise((resolve,reject)=>reject('err')));
            } catch (error) {
                console.log(error);
            }
            
        }

        main();
    </script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tjrhqirl-1679284523338)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1669690975393.png)]

1.12.12 async与await结合实践
// 读取resources文件夹下的1、2、3.html文件

const fs = require('fs');
const util = require('util');
const readF = util.promisify(fs.readFile)

// 传统方式读取
// fs.readFile('./resources/1.html',(err,data1)=>{
//     if(err) throw err;
//     fs.readFile('./resources/2.html',(err,data2)=>{
//         if(err) throw err;
//         fs.readFile('./resources/3.html',(err,data3)=>{
//             if(err) throw err;
//             console.log(data1+'--'+data2+'--'+data3);
//         })
//     })
// })

// async与await结合方式


async function main(){
    try {
        let data1 = await readF('./resources/13.html');
        let data2 = await readF('./resources/2.html');
        let data3 = await readF('./resources/3.html');
        console.log(data1+'--'+data2+'--'+data3);
    } catch (error) {
        console.log(error);
    }
    
};

main();
1.12.13 async结合await发送ajax

客户端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;padding: 0;
        }
        .shi {
            width: 200px;
            height: 200px;
            background-color: aqua;
            font-size: 30px;
        }
    </style>
</head>
<body>
    <button>点击获取《静夜思》</button>
    <div class="shi">

    </div>

    <script>

        let btn = document.querySelector('button');
        let shi = document.querySelector('.shi');
        function sendAjax(method,url){
            return new Promise((resolve,reject)=>{
                const xhr = new XMLHttpRequest();
                xhr.open(method,url);
                xhr.send();
                xhr.onreadystatechange = function(){
                    if(xhr.readyState===4){
                        if(xhr.status>=200&&xhr.status<300)resolve(xhr.response);
                        else reject(xhr.status);
                    }
                }
                
            })
        }
        
        btn.addEventListener('click',function(){
            let ajax = sendAjax('GET','http://localhost:9000/shi');
            ajax.then(value=>{
            console.log(value);
            shi.innerHTML = value
            },reason=>{
                console.warn(reason);
            })
        })
             
</script>
</body>
</html>

服务端

const express = require('express');

const app = express();

app.get('/shi',(req,res)=>{
    res.setHeader('Access-Control-Allow-Origin','*')
    // 允许自定义请求头信息
    res.setHeader('Access-Control-Allow-Headers','*');
    let = data = {
        name:'liang',
        age:18
    }
    let str = '<p>床前明月光<br/>疑是地上霜<br/>举头望明月<br/>低头思故乡<br/></p>';
    res.send(str)
})

app.listen(9000,()=>{
    console.log('espress is running at http://localhost:9000/');
})

1.13 Set

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口, 所以可以使用『扩展运算符』和『for…of…』进行遍历 。

  • size:返回集合的元素个数
  • add():增加一个新元素,返回当前集合
  • delete():删除元素,返回 boolean 值
  • has():检测集合中是否包含某个元素,返回 boolean 值
  • clear():清空集合,返回 undefined

1.14 Map

是键值对的集合。但是“键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 iterator 接口, 所以可以使用『扩展运算符』和『for…of…』进行遍历

  • size:返回 Map 的元素个数
  • set():增加一个新元素,返回当前 Map
  • get():返回键名对象的键值
  • has():检测 Map 中是否包含某个元素,返回 boolean 值
  • clear():清空集合,返回 undefined

1.15 class

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是 一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已(React类组件用到)

1.16 数值扩展

1.16.1 二八进制
let b = 0b1010//二进制
let o = 0o777;//八进制
let d = 100;//十进制
let x = 0xff;//十六进制
console.log(b);
console.log(o);
console.log(d);
console.log(x);
1.16.2 Number.EPSILON

Number.EPSILON:它是 JavaScript 表示的最小精度,EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16

function equal(a, b) {
    if (Math.abs(a - b) < Number.EPSILON) {
        return true;
    } else {
        return false;
    }
}
console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1 + 0.2, 0.3));
1664009427474
1.16.3 Number.isFinite()
// Number.isFinite:检测一个数值是否为有限数
console.log(Number.isFinite(100));
console.log(Number.isFinite(100 / 0));
console.log(Number.isFinite(Infinity));
console.log(Number.isFinite(-Infinity));
1.16.4 Number.isNaN()
// 检测一个数值是否为 NaN
console.log(Number.isNaN(123));
1.16.7、Number.isInteger()
// 判断一个数是否为整数
console.log(Number.isInteger(5));
console.log(Number.isInteger(2.5));
1.16.8、Math.trunc()
//将数字的小数部分抹掉
console.log(Math.trunc(3.5));

1.17、对象扩展

  • Object.is():比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
console.log(Object.is(120, 120));// ===
console.log(Object.is(NaN, NaN));// ===
console.log(NaN === NaN);// ==

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1bhll1jO-1679284523339)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664009919635.png)]

  • Object.assign():对象的合并,将源对象的所有可枚举属性,复制到目标对象
const config1 = {
    host: "localhost",
    port: 3306,
    name: "zhangsan",
    pass: "root",
    test1: "test1"
};
const config2 = {
    host: "127.0.0.1",
    port: 3309,
    name: "lisi",
    pass: "root",
    test2: "test2"
}
console.log(Object.assign(config1, config2));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SKF3zPxM-1679284523340)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664010042281.png)]

  • proto、setPrototypeOf、 setPrototypeOf可以直接设置对象的原型
const school = {
    name: "MySchool"
};
const cities = {
    xiaoqu: ["北京", "上海", "深圳"]
};
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3oKUSxs-1679284523341)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664010276697.png)]

1.18 模块化

1.18.1、模块化的好处
  • 防止命名冲突
  • 代码复用
  • 高维护性

模块功能主要由两个命令构成:export 和 import。

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其它模块提供的功能
//导出(略)
	// 导入 m1.js 模块内容
	import * as m1 from "./m1.js";
    // 引入 m2.js 模块内容
    import * as m2 from "./m2.js";
    // 引入 m3.js 模块内容
    import * as m3 from "./m3.js";

1.19 浅拷贝与深拷贝

1.19.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);
1.19.2 深拷贝
  • 一维数组的深拷贝
// slice()
var arr1 = [1, 2, 3, 4];
var arr2 = arr1.slice();
arr2[0] = 200;
console.log(arr1);
console.log(arr2);

//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.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 = "李四";
console.log(obj1);
console.log(obj2);
1.19.3 对象深拷贝通用法
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 = "李四";
console.log(obj1);
console.log(obj2);

/**
 * 深拷贝通用方法
 * @param obj   需要拷贝的对象
 * @param has
 * @returns {any|RegExp|Date}
 */
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;
}

2 ES7(待续)

2.1 数组方法扩展

includes():此方法用来检测数组中是否包含某个元素,返回布尔类型值

    var arr1 = [1, 2, 3, 4];
    console.log(arr1.includes(5));
    console.log(arr1.includes(4));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Ab4PI5P-1679284523342)(C:\Users\liangrz\AppData\Roaming\Typora\typora-user-images\1664011941594.png)]

2.2 幂运算

// **操作和Math.pow(底数,指数)功能一样
console.log(2 ** 10);
console.log(Math.pow(2, 10));

3 ES8(待续)

4 ES9(待续)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rLXkTgv3-1679284523343)(E:\study\前端\js\1664520576932.png)]

5 ES10(待续)

6 ES11(待续)

案例

11.1 可拖动的模态框

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .login-header {
            width: 100%;
            text-align: center;
            height: 30px;
            font-size: 24px;
            line-height: 30px;
        }
 
        ul,
        li,
        ol,
        dl,
        dt,
        dd,
        div,
        p,
        span,
        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
        a {
            padding: 0px;
            margin: 0px;
        }
 
        .login {
            display: none;
            /* 先给模态框设置隐藏 */
            position: fixed;
            /* 给模态框加一个固定定位 */
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            /* 以上三句话加上定位,实现login模态框在浏览器中水平和垂直居中 */
            background: #ffffff;
            box-shadow: 0px 0px 20px #ddd;
            z-index: 9999;
            border: #ebebeb solid 1px;
            width: 512px;
            height: 280px;
        }
 
        .login-title {
            width: 100%;
            margin: 10px 0px 0px 0px;
            text-align: center;
            line-height: 40px;
            height: 40px;
            font-size: 18px;
            position: relative;
            cursor: move;
        }
 
        .login-input-content {
            margin-top: 20px;
        }
 
        .login-button {
            width: 50%;
            margin: 30px auto 0px auto;
            line-height: 40px;
            font-size: 14px;
            border: #ebebeb 1px solid;
            text-align: center;
        }
 
        .login-bg {
            display: none;
            /* 先给模态框的背景也设置隐藏 */
            width: 100%;
            height: 100%;
            position: fixed;
            top: 0px;
            left: 0px;
            background: rgba(0, 0, 0, .3);
        }
 
        a {
            text-decoration: none;
            color: #000000;
        }
 
        .login-button a {
            display: block;
        }
 
        .login-input input.list-input {
            float: left;
            line-height: 35px;
            height: 35px;
            width: 350px;
            border: #ebebeb 1px solid;
            text-indent: 5px;
        }
 
        .login-input {
            overflow: hidden;
            margin: 0px 0px 20px 0px;
        }
 
        .login-input label {
            float: left;
            width: 90px;
            padding-right: 10px;
            text-align: right;
            line-height: 35px;
            height: 35px;
            font-size: 14px;
        }
 
        .login-title span {
            position: absolute;
            font-size: 12px;
            right: -20px;
            top: -30px;
            background: #ffffff;
            border: #ebebeb solid 1px;
            width: 40px;
            height: 40px;
            border-radius: 20px;
            cursor: pointer;
            /* 当鼠标点击到login模态框中的span区域,鼠标变为小手 */
        }
    </style>
</head>
 
<body>
    <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
    <div id="login" class="login">
        <div id="title" class="login-title">登录会员
            <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
        </div>
        <div class="login-input-content">
            <div class="login-input">
                <label>用户名:</label>
                <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
            </div>
            <div class="login-input">
                <label>登录密码:</label>
                <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
            </div>
        </div>
        <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
    </div>
    <!-- 遮盖层 -->
    <div id="bg" class="login-bg"></div>
    <script>
        // 1. 获取元素
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var title = document.querySelector('#title');
        var span = document.querySelector('span');
        // 2. 点击弹出层这个链接 link,让模态框背景mask 和 模态框login 显示出来
        link.addEventListener('click', function () {
            mask.style.display = 'block';
            login.style.display = 'block';
        })
        // 3. 点击 span,隐藏 模态框背景mask 和 模态框login 
        span.addEventListener('click', function (e) {
            mask.style.display = 'none';
            login.style.display = 'none';
            e.stopPropagation();
            //解决添加了鼠标按下事件(mousedown)后,由于默认是冒泡,会导致点击login模态框的子级span也可以移动模态框的BUG
        })
        // 4. 开始拖拽
        // (1) 当鼠标在模态框中的title区域按下,获得鼠标在盒子内的坐标
        title.addEventListener('mousedown', function (e) {
            // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;
            document.addEventListener('mousemove', move);
            // 只有按下(mousedown)后才能拖动鼠标(mousemove),所以mousemove要写在mousedown里面
            //在页面中任意地方都可以移动鼠标,所有用document绑定事件
            function move(e) {
                login.style.left = e.pageX - x + 'px';
                login.style.top = e.pageY - y + 'px';
                //注意:e.pageX,e.pageY,e.offsetLeft,e.offsetTop返回的值都没有单位,所以要用拼接字符串加上单位
            }
            // (3) 当鼠标在浏览器中任意地方弹起的时候(所以依然用document绑定事件),移除之前绑定的鼠标移动(mousemove)的事件(move)
            document.addEventListener('mouseup', function () {
                document.removeEventListener('mousemove', move);
            })
        })
 
    </script>
</body>
 
</html>

: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}

    .login-input-content {
        margin-top: 20px;
    }

    .login-button {
        width: 50%;
        margin: 30px auto 0px auto;
        line-height: 40px;
        font-size: 14px;
        border: #ebebeb 1px solid;
        text-align: center;
    }

    .login-bg {
        display: none;
        /* 先给模态框的背景也设置隐藏 */
        width: 100%;
        height: 100%;
        position: fixed;
        top: 0px;
        left: 0px;
        background: rgba(0, 0, 0, .3);
    }

    a {
        text-decoration: none;
        color: #000000;
    }

    .login-button a {
        display: block;
    }

    .login-input input.list-input {
        float: left;
        line-height: 35px;
        height: 35px;
        width: 350px;
        border: #ebebeb 1px solid;
        text-indent: 5px;
    }

    .login-input {
        overflow: hidden;
        margin: 0px 0px 20px 0px;
    }

    .login-input label {
        float: left;
        width: 90px;
        padding-right: 10px;
        text-align: right;
        line-height: 35px;
        height: 35px;
        font-size: 14px;
    }

    .login-title span {
        position: absolute;
        font-size: 12px;
        right: -20px;
        top: -30px;
        background: #ffffff;
        border: #ebebeb solid 1px;
        width: 40px;
        height: 40px;
        border-radius: 20px;
        cursor: pointer;
        /* 当鼠标点击到login模态框中的span区域,鼠标变为小手 */
    }
</style>
~~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值