文章目录
前端学习–js部分下
1.作用域
1.1局部作用域
1.2全局作用域
1.3作用域链
1.4垃圾回收机制
1.4.1垃圾回收机制算法
1.5闭包
小结
1.6变量提升
小结
变量提升是把var变量提升到当前作用域于最前面,然后依次执行代码。需要注意的是只提升变量声明, 不提升变量赋值。不过我们不建议使用var来声明变量。
2.函数
2.1函数提升
2.2函数参数
我们要学习并使用动态参数和剩余参数,提升函数应用的灵活性。
2.2.1动态参数
小结
2.2.2剩余参数
<script> function getSum(a, b, ...arr) { console.log(arr) // 使用的时候不需要写 ... } getSum(2, 3) // [] getSum(1, 2, 3, 4, 5) // [3,4,5] </script>
小结
2.2.3展开运算符
小结
2.3箭头函数 (重要)
<body> <script> const f = function () { console.log('普通函数') } f() // 箭头函数 // 1.基本写法 const fn = (x) => { console.log(x) } fn(1) // 2.只有一个形参时可以省略小括号 const fun = x => { console.log(x) } fun(2) // 3.只有一行代码时可以省略大括号 const func = x => console.log(x) func(3) </script> </body>
小结
<script> // 以前this的指向: 谁调用的这个函数,this 就指向谁 // console.log(this) // window // // 普通函数 // function fn() { // console.log(this) // window // } // window.fn() // // 对象方法里面的this // const obj = { // name: 'andy', // sayHi: function () { // console.log(this) // obj // } // } // obj.sayHi() // 2. 箭头函数的this 是上一层作用域的this 指向 // const fn = () => { // console.log(this) // window // } // fn() // 对象方法箭头函数 this // const obj = { // uname: 'pink老师', // sayHi: () => { // console.log(this) // this 指向谁? window // } // } // obj.sayHi() const obj = { uname: 'pink老师', sayHi: function () { console.log(this) // obj let i = 10 const count = () => { console.log(this) // obj } count() } } obj.sayHi() </script>
事件回调函数与箭头函数
小结
3.解构赋值
3.1数组解构
<body> <script> // 1.变量多, 单元值少 , undefined /* const [a, b, c, d] = [1, 2, 3] console.log(a) // 1 console.log(b) // 2 console.log(c) // 3 console.log(d) // undefined */ // 2.变量少, 单元值多 /* const [a, b] = [1, 2, 3] console.log(a) // 1 console.log(b) // 2 */ // 3.剩余参数 变量少, 单元值多 但只能置于最末位,返回的还是一个数组 /* const [a, b, ...c] = [1, 2, 3, 4] console.log(a) // 1 console.log(b) // 2 console.log(c) // [3, 4] 真数组 */ // 4.防止 undefined 传递 只有单元值为 undefined 时默认值才会生效 /* const [a = 0, b = 0] = [1, 2] const [c = 0, d = 0] = [] console.log(a) // 0 console.log(b) // 0 */ // 5.按需导入赋值 自动跳过某一值 /* const [a, b, , d] = [1, 2, 3, 4] console.log(a) // 1 console.log(b) // 2 console.log(d) // 4 */ // 6.多维数组解构 // const [a, b, c] = [1, 2, [3, 4]] // console.log(a) // 1 // console.log(b) // 2 // console.log(c) // [3,4] const [a, b, [c, d]] = [1, 2, [3, 4]] console.log(a) // 1 console.log(b) // 2 console.log(c) // 3 console.log(d) // 4 </script> </body>
小结
3.2对象结构
<script> //普通对象 // const obj = { // uname: 'pink老师', // age: 18 // } // 对象解构 解构语法 const { uname, age } = {age: 18, uname: 'pink老师' } // 等价于 const uname = obj.uname // 要求属性名和变量名必须一直才可以 console.log(uname) console.log(age) </script>
**2.给新的变量名赋值:**可以从一个对象中提取变量并同时修改新的变量名
<script> // 对象解构的变量名 可以重新改名 旧变量名: 新变量名 const { uname: username, age } = { uname: 'pink老师', age: 18 } console.log(username) console.log(age) </script>
3. 数组对象解构
<script> // 解构数组对象 const pig = [ { uname: '佩奇', age: 6 } ] const [{ uname, age }] = pig console.log(uname) console.log(age) </script>
4.多级对象结构
<script> // 多级对象结构的两种写法 // const pig = { // name: '佩奇', // family: { // mother: '猪妈妈', // father: '猪爸爸', // sister: '乔治' // }, // age: 6 // } // // 多级对象解构 // const { name, family: { mother, father, sister } } = pig // console.log(name) // console.log(mother) // console.log(father) // console.log(sister) const person = [ { name: '佩奇', family: { mother: '猪妈妈', father: '猪爸爸', sister: '乔治' }, age: 6 } ] const [{ name, family: { mother, father, sister } }] = person console.log(name) console.log(mother) console.log(father) console.log(sister) </script>
4.遍历数组 forEach 方法(重点)
需要注意的是 forEach 主要用于遍历数组,我们使用 forEach 时,参数中的当前数组元素是必须要写的,当前元素索引号可写可不写。
5.筛选数组 filter 方法(重点)
使用filter() 方法,创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
主要使用场景: 筛选数组中符合条件的元素。
语法:// currentValue指的是条件 // currentValue必须写,index可写可不写 被遍历的数组.filter(function (currentValue, index) { return 筛选条件 })
**注意:**因为返回新数组,所以不会影响原数组。
6.深入对象
6.1创建对象的三种方式
1.利用对象字面量创建对象
const o={ name:'字面量' }
2.利用new Object创建对象
<script> // const obj = new Object() // obj.uname = 'peter' // console.log(obj) const obj = new Object({ uname: 'peter' }) console.log(obj) </script>
3.利用构造函数创建对象
6.2构造函数
构造函数是一种特殊的函数,它主要用于初始化对象。
**使用场景:**使用构造函数来快速创建多个类似的对象,增强代码的复用性。
**注意:**构造函数的命名必须以大写字母开头,所以大写字母开头的函数就是构造函数,并且他们只能用“new”操作符来执行。
<script> // 创建一个猫 构造函数 function Cat(uname, age) { this.uname = uname this.age = age } // console.log(new Cat('咪咪', 6)) // console.log(new Cat('花花', 3)) const p = new Cat('咪咪', 6) console.log(p) </script>
说明:
1.使用new关键字调用函数的行为被称为实例化
2.实例化构造函数时没有参数时可以省略括号
3.构造函数内部无需写return,返回值即为新创建的对象,即自动返回创建的新对象。
6.3实例成员
**实例成员:**通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员。
// 构造函数 function Person() { // 构造函数内部的this就是实例对象 // 实例对象动态添加属性 this.name = '小明' // 实例对象动态添加方法 this.sayHi = function () { console.log('Hi~') } } // p1就是实例对象 是构造函数内部的this const p1 = new Person() console.log(p1) console.log(p1.name)
说明:
1.为构造函数传入参数,就是动态创建结构相同但值不同的对象。
2.构造函数创建的实例对象彼此独立互不影响
6.4静态成员
构造函数中的属性和方法被称为静态成员。
// 构造函数 function Person() { //省略实例成员 } // 静态属性 Person.eyes = 2 Person.mouth = 1 // 静态方法 Person.walk = function () { console.log('散步~') // this指向Person console.log(this.eyes) }
**说明:**一般把一些公共的属性或方法设置为静态成员
7.内置构造函数
前言
在 JavaScript 中最主要的数据类型有 6 种,分别是字符串、数值、布尔、undefined、null、对象。
基本数据类型: 字符串、数值、布尔、undefined、null
引用类型: 对象(数组、函数都属于对象)
**特殊情况:**字符串、数值、布尔等作为简单数据类型也有方法,因为 js 在底层将简单数据类型包装成引用数据类型(复杂数据类型)。
注意:
其实字符串、数值、布尔、等基本类型也都有专门的构造函数,这些我们称为包装类型 。
js 中几乎所有的数据都可以基于构造函数创建。
**内置构造函数:**Object、Array、String、Number。
内置构造函数有两类:
**1.引用类型 :**Object,Array,RegExp,Date 等。
**2.包装类型 :**String,Number,Boolean 等。
7.1 Object
Object 用于创建普通对象。但是我们推荐使用字面量方式声明对象,而不是 Object 内置构造函数。下面我们将介绍一下,只有它可以调用的三个静态方法。
1.Object.keys
它的作用是可以获取对象中所有属性(键),返回值是一个数组。
<script> const o = { uname: 'pink', age: 18 } // 获得所有的属性名 console.log(Object.keys(o)) //返回数组['uname', 'age'] </script>
2. Object.values
它的作用是获取对象中所有属性值,返回值同样是一个数组。
<script> const o = { uname: 'pink', age: 18 } // 获得所有的属性值 console.log(Object.values(o)) // ['pink', 18] </script>
3. Object. assign
它的作用是对象拷贝,使用的场景是给对象添加属性。
<script> const o = { uname: 'pink', age: 18 } // 对象拷贝 // const oo = {} // Object.assign(oo, o) // console.log(oo) Object.assign(o, { gender: '女' }) console.log(o) </script>
7.2 Array
它用于创建数组。创建数组推荐使用字面量创建,不用Array构造函数创建。
<script> const arr = new Array(3, 5) console.log(arr) // [3,5] </script>
1. 数组常见实例方法-核心方法
reduce()
// reduce()语法 // 起始值可以省略,如果写就作为第一次累计的起始值。 //累计值prev,当前元素current // arr.reduce(function(累计值(上一次值), 当前值){}, 起始值)
累计值参数说明:
1.如果有起始值,则以起始值为准开始累计
2.如果没有起始值, 则累计值以数组的第一个数组元素作为起始值开始累计
3.后面每次遍历就会用后面的数组元素 累计到 累计值 里面 (类似求和里面的 sum )
<script> const arr = [1, 2, 3] const re = arr.reduce((prev, current) => prev + current) //有起始值的时候 //const re = arr.reduce((prev, current) => prev + current,10) console.log(re) </script>
2. 数组常见方法-其他方法
3. 数组常见方法- 伪数组转换为真数组
<script> // 静态方法 Array.from() // Array.from(lis) 把伪数组转换为真数组 const lis = document.querySelectorAll('ul li') // console.log(lis) // lis.pop() 报错 const liss = Array.from(lis) liss.pop() console.log(liss) </script>
7.3 String
1. 字符串常见实例方法
<script> //1. split把字符串转换为数组和 join() 相反 // const str = 'pink,red' // const arr = str.split(',') // console.log(arr) // const str1 = '2022-4-8' // const arr1 = str1.split('-') // console.log(arr1) // 2. 字符串的截取 substring(开始的索引号[, 结束的索引号]) // 2.1 如果省略 结束的索引号,默认取到最后 // 2.2 结束的索引号不包含想要截取的部分 // const str = '今天又要做核酸了' // console.log(str.substring(5, 7)) // [5,7) // 3. startsWith 判断是不是以某个字符开头 // const str = 'pink老师上课中' // console.log(str.startsWith('pink')) // 4. includes 判断某个字符是不是包含在一个字符串里面 const str = '我是pink老师' console.log(str.includes('pink')) // true </script>
7.4 Number
它用于创建数值。
1.常用方法
<script> // toFixed 方法可以让数字指定保留的小数位数 const num = 10.923 // console.log(num.toFixed()) //保留一位小数 四舍五入 console.log(num.toFixed(1)) const num1 = 10 console.log(num1.toFixed(2)) </script>
8.编程思想
8.1面向过程编程
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用函数就可以了。简单来讲,就是按照我们分析好了的步骤解决问题。
8.2面向对象编程(oop)
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。划分的问题是基于对象的功能,而不是步骤。在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工。
面向对象编程具有灵活性强、代码的复用性较高、容易维护和开发的优点,更适合多人合作的大型软件项目。
面向对象的特性: 封装性、继承性、多态性。8.3面向过程和面向对象的对比
**注意:**前端不同于其他语言,面向过程编程更多。
9.构造函数的封装性
10.原型
10.1原型对象–实际上就是原型
10.1.2 this指向
构造函数和原型对象中的 this 都指向实例化的对象。
10.1.3 constructor 属性
**小结:**constructor 属性的作用是指向该原型对象的构造函数。
10.2对象原型–实际上是对象的原型
实例对象可以访问原型对象的原因是因为对象原型(
__proto__
)。这句话是分清原型对象和对象原型的关键。
说明:
1.
__proto__
是 js 非标准属性,[[prototype]]和__proto__
意义相同。谷歌浏览器会显示[[prototype]]2.用来表明当前实例对象指向哪个原型对象prototype
3.
__proto__
对象原型里面也有一个 constructor属性, 指向创建该实例对象的构造函数4.对象中都会有一个
__proto__
属性指向构造函数中的prototype小结(重点)
- prototype是什么?哪里来的?
原型(原型对象)
构造函数都自动有原型- constructor属性在哪里?作用干啥的?
prototype原型和对象原型__proto__
里面都有
都 指向 创建实例对象/原型的 构造函数__proto__
属性在哪里?指向谁?
在实例对象里面(是对象就有)
指向原型 prototype10.3原型继承
**1.封装:**抽取公共部分
**2.继承:**让男人和女人都能继承人类公共的一些属性和方法
<script> // 继续抽取 公共的部分放到原型上 // 构造函数 new 出来的对象 结构一样,但是对象不一样 function Person() { this.eyes = 2 this.head = 1 } // console.log(new Person) // 女人 构造函数 继承 想要 继承 Person function Woman() { } // Woman 通过原型来继承 Person // 父构造函数(父类) 子构造函数(子类) // 子类的原型 = new 父类 Woman.prototype = new Person() // {eyes: 2, head: 1} // 指回原来的构造函数 Woman.prototype.constructor = Woman // 给女人添加一个方法 生孩子 Woman.prototype.baby = function () { console.log('宝贝') } const red = new Woman() console.log(red) // console.log(Woman.prototype) // 男人 构造函数 继承 想要 继承 Person function Man() { } // 通过 原型继承 Person Man.prototype = new Person() Man.prototype.constructor = Man const pink = new Man() console.log(pink) </script>
问题: 如果我们给女人添加了一个baby的方法,发现男人自动也添加这个方法
原因: 男人和女人都同时使用了同一个对象,根据引用类型的特点,修改一个就会两个都影响。
**解决:**男人和女人不要使用同一个对象,但是为了提高代码的复用性,不让不同对象里面包含相同的属性和方法,我们要使用构造函数,让 new 每次都创建一个新的对象。(实际代码见上)
10.4原型链
<script> // function Objetc() {} console.log(Object.prototype) console.log(Object.prototype.__proto__) function Person() { } const ldh = new Person() // console.log(ldh.__proto__ === Person.prototype) // console.log(Person.prototype.__proto__ === Object.prototype) console.log(ldh instanceof Person) console.log(ldh instanceof Object) console.log(ldh instanceof Array) console.log([1, 2, 3] instanceof Array) console.log(Array instanceof Object) </script> </body>
11.综合案例
渲染商品列表案例
<body> <div class="list"> <!-- <div class="item"> <img src="" alt=""> <p class="name"></p> <p class="price"></p> </div> --> </div> <script> const goodsList = [ { id: '4001172', name: '称心如意手摇咖啡磨豆机咖啡豆研磨机', price: '289.00', picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg', }, { id: '4001594', name: '日式黑陶功夫茶组双侧把茶具礼盒装', price: '288.00', picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg', }, { id: '4001009', name: '竹制干泡茶盘正方形沥水茶台品茶盘', price: '109.00', picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png', }, { id: '4001874', name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器', price: '488.00', picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png', }, { id: '4001649', name: '大师监制龙泉青瓷茶叶罐', price: '139.00', picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png', }, { id: '3997185', name: '与众不同的口感汝瓷白酒杯套组1壶4杯', price: '108.00', picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg', }, { id: '3997403', name: '手工吹制更厚实白酒杯壶套装6壶6杯', price: '99.00', picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg', }, { id: '3998274', name: '德国百年工艺高端水晶玻璃红酒杯2支装', price: '139.00', picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg', }, ] // 1. 声明一个字符串变量 let str = '' // 2. 遍历数据 goodsList.forEach(item => { // console.log(item) // 可以得到每一个数组元素 对象 {id: '4001172'} // const {id} = item 对象解构 const { name, price, picture } = item str += ` <div class="item"> <img src=${picture} alt=""> <p class="name">${name}</p> <p class="price">${price}</p> </div> ` }) // 3.生成的 字符串 添加给 list document.querySelector('.list').innerHTML = str </script> </body>
商品列表价格筛选
<body> <div class="filter"> <a data-index="1" href="javascript:;">0-100元</a> <a data-index="2" href="javascript:;">100-300元</a> <a data-index="3" href="javascript:;">300元以上</a> <a href="javascript:;">全部区间</a> </div> <div class="list"> <!-- <div class="item"> <img src="" alt=""> <p class="name"></p> <p class="price"></p> </div> --> </div> <script> // 初始化数据 const goodsList = [ { id: '4001172', name: '称心如意手摇咖啡磨豆机咖啡豆研磨机', price: '289.00', picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg', }, { id: '4001594', name: '日式黑陶功夫茶组双侧把茶具礼盒装', price: '288.00', picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg', }, { id: '4001009', name: '竹制干泡茶盘正方形沥水茶台品茶盘', price: '109.00', picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png', }, { id: '4001874', name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器', price: '488.00', picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png', }, { id: '4001649', name: '大师监制龙泉青瓷茶叶罐', price: '139.00', picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png', }, { id: '3997185', name: '与众不同的口感汝瓷白酒杯套组1壶4杯', price: '108.00', picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg', }, { id: '3997403', name: '手工吹制更厚实白酒杯壶套装6壶6杯', price: '100.00', picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg', }, { id: '3998274', name: '德国百年工艺高端水晶玻璃红酒杯2支装', price: '139.00', picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg', }, ] // 1. 渲染函数 封装 function render(arr) { // 声明空字符串 let str = '' // 遍历数组 arr.forEach(item => { // 解构 const { name, picture, price } = item str += ` <div class="item"> <img src=${picture} alt=""> <p class="name">${name}</p> <p class="price">${price}</p> </div> ` }) // 追加给 List document.querySelector('.list').innerHTML = str } render(goodsList) // 2.过滤筛选 document.querySelector('.filter').addEventListener('click', e => { const { tagName, dataset } = e.target // 判断 if (tagName === 'A') { // arr 返回的新数组 let arr = goodsList if (dataset.index === '1') { arr = goodsList.filter(item => item.price > 0 && item.price <= 100) } else if (dataset.index === '2') { arr = goodsList.filter(item => item.price >= 100 && item.price <= 300) } else if (dataset.index === '3') { arr = goodsList.filter(item => item.price >= 300) } // 渲染函数 render(arr) } }) </script> </body>
显示赠品
<script> const gift = '50g的茶叶,清洗球' // 1. 把字符串拆分为数组 // console.log(gift.split(',')) [,] // 2. 根据数组元素的个数,生成 对应 span标签 // const str = gift.split(',').map(function (item) { // return `<span>【赠品】 ${item}</span> <br>` // }).join('') // // console.log(str) // document.querySelector('div').innerHTML = str document.querySelector('div').innerHTML = gift.split(',').map(item => `<span>【赠品】 ${item}</span> <br>`).join('') </script>
购物车展示
<body> <div class="list"> <!-- <div class="item"> <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt=""> <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p> <p class="spec">白色/10寸</p> <p class="price">289.90</p> <p class="count">x2</p> <p class="sub-total">579.80</p> </div> --> </div> <div class="total"> <div>合计:<span class="amount">1000.00</span></div> </div> <script> const goodsList = [ { id: '4001172', name: '称心如意手摇咖啡磨豆机咖啡豆研磨机', price: 289.9, picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg', count: 2, spec: { color: '白色' } }, { id: '4001009', name: '竹制干泡茶盘正方形沥水茶台品茶盘', price: 109.8, picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png', count: 3, spec: { size: '40cm*40cm', color: '黑色' } }, { id: '4001874', name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器', price: 488, picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png', count: 1, spec: { color: '青色', sum: '一大四小' } }, { id: '4001649', name: '大师监制龙泉青瓷茶叶罐', price: 139, picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png', count: 1, spec: { size: '小号', color: '紫色' }, gift: '50g茶叶,清洗球,宝马, 奔驰' } ] // 1. 根据数据渲染页面 document.querySelector('.list').innerHTML = goodsList.map(item => { // console.log(item) // 每一条对象 // 对象解构 item.price item.count const { picture, name, count, price, spec, gift } = item // 规格文字模块处理 const text = Object.values(spec).join('/') // 计算小计模块 单价 * 数量 保留两位小数 // 注意精度问题,因为保留两位小数,所以乘以 100 最后除以100 const subTotal = ((price * 100 * count) / 100).toFixed(2) // 处理赠品模块 '50g茶叶,清洗球' const str = gift ? gift.split(',').map(item => `<span class="tag">【赠品】${item}</span> `).join('') : '' return ` <div class="item"> <img src=${picture} alt=""> <p class="name">${name} ${str} </p> <p class="spec">${text} </p> <p class="price">${price.toFixed(2)}</p> <p class="count">x${count}</p> <p class="sub-total">${subTotal}</p> </div> ` }).join('') // 3. 合计模块 const total = goodsList.reduce((prev, item) => prev + (item.price * 100 * item.count) / 100, 0) // console.log(total) document.querySelector('.amount').innerHTML = total.toFixed(2) </script> </body>
消息提示对象封装
<body> <button id="delete">删除</button> <button id="login">登录</button> <!-- <div class="modal"> <div class="header">温馨提示 <i>x</i></div> <div class="body">您没有删除权限操作</div> </div> --> <script> // 1. 模态框的构造函数 function Modal(title = '', message = '') { // 创建 modal 模拟框盒子 // 1.1 创建 div 标签 this.modalBox = document.createElement('div') // 1.2 给 div 标签添加类名为 modal this.modalBox.className = 'modal' // 1.3 modal 盒子内部填充 2个 div 标签并且修改文字内容 this.modalBox.innerHTML = ` <div class="header">${title}<i>x</i></div> <div class="body">${message}</div> ` } // 2.给构造函数原型对象挂载 open 方法 Modal.prototype.open = function () { // 先来判断页面中是否有 modal 盒子,如果有先删除,否则继续添加 const box = document.querySelector('.modal') box && box.remove() // 注意这个方法不要用箭头函数 // 把刚才创建的 modalBox 显示到页面 body 中 document.body.append(this.modalBox) // 要等着盒子显示出来,就可以绑定点击事件了 this.modalBox.querySelector('i').addEventListener('click', () => { // 这个地方需要用到箭头函数 // 这个 this 指向实例对象 this.close() }) } // 3. 关闭方法 挂载 到 模态框的构造函数原型身上 Modal.prototype.close = function () { this.modalBox.remove() } // 4. 按钮点击 document.querySelector('#delete').addEventListener('click', () => { const m = new Modal('温馨提示', '您没有权限删除') // 调用 打开方法 m.open() }) // 5. 按钮点击 document.querySelector('#login').addEventListener('click', () => { const m = new Modal('友情提示', '您还么有注册账号') // 调用 打开方法 m.open() }) </script> </body>