JS 进阶3——深入面向对象、原型
1.编程思想
- 面向过程:分析出解决问题的过程,然后用函数将这些步骤一步步封装起来
- 面向对象:将事物分为一个个对象,然后对象之间分工合作
2.构造函数:封装性、面向对象
-
构造函数方法存在浪费内存的问题(构造函数中的方法每次调用)
function Star(name, age) { this.name = name this.age = age this.sing = function () { console.log('我会唱歌') } } const xxg = new Star('小小怪', 18) const ddg = new Star('大大怪', 22) console.log(xxg.sing === ddg.sing) //返回false,重复创建两个sing
3.原型——解决构造函数浪费内存的问题
-
什么是原型
- 构造函数通过原型分配的函数是所有对象所共享的
- JS中,每个构造函数都有一个prototype属性,指向另一个对象,称为原型对象
- 原型对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
- 可以把不变的方法直接定义到prototype对象上,这样所有对象的实例可以共享这些方法
- 构造函数和原型对象中的this都指向实例化的对象
//1.公共属性写到构造函数中 function Star(name, age) { this.name = name this.age = age } //2.公共方法写到原型对象身上 Star.prototype.sing = function () { console.log('唱歌'); } const xxg = new Star('小小怪', 18) const ddg = new Star('大大怪', 22) xxg.sing() ddg.sing() console.log(xxg.sing === ddg.sing) //返回true
eg:为数组对象添加方法(注意想要不传参,就要使用this指向实例对象)
//为数组拓展 求最大值方法 Array.prototype.max = function () { return Math.max(...this) } //为数组拓展 求和方法 Array.prototype.sum = function () { return this.reduce((prev, current) => prev + current) } const str = [1, 2, 3] console.log(str.max()) console.log(str.sum())
-
constructor(构造函数)属性
- 每个原型对象中都有一个constructor属性
- 该属性指向该原型对象的构造函数,标明该原型对象属于哪个构造函数
//创建一个构造函数 function Star() { } //想要为该构造函数一次性挂载多个方法 Star.prototype = { //重新指回创造这个原型对象的构造函数 constructor: Star, sing: function () { console.log('我喜欢唱歌'); }, dance: function () { console.log('我喜欢跳舞'); } } console.log(Star.prototype) //返回undefined //意味着找不到该原型对象的构造函数了 //解决办法:在原型对象中重新指回创造这个原型对象的构造函数
-
对象原型
- 对象都会有一个 __ proto__ 指向构造函数的prototype原型对象,之所以对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象 __ proto __ 的存在
- 只能获取不能赋值
- 对象原型是实例对象的属性,指向原型对象,有一个属性constructor指向构造函数;原型对象是构造函数的属性,是一个对象,也有一个属性constructor指向构造函数
function Star() { } const ldh = new Star() console.log(ldh.__proto__ === Star.prototype) //返回true
-
原型继承
- 借助原型对象实现继承的特性
//人 父构造函数 function People() { this.eyes = 2 this.head = 1 } //女人 构造函数 继承People function Woman() { } //子类的原型 = new 父类,方便给子类添加特殊的属性和方法 Woman.prototype = new People() //指回构造函数 Woman.prototype.constructor = Woman //给女人添加方法 Woman.prototype.baby = function () { console.log('宝贝') } const red = new Woman() console.log(red) //男人 构造函数 继承People function Man() { } Man.prototype = new People() Man.prototype.constructor = Man const blue = new Man() console.log(blue)
-
原型链:就是一个查找规则,先从自身原型对象查找属性和方法,找不到就往上一层查找,原型链就是往上查找的这样一个路线。
- instanceof运算符:用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
- 案例:使用原型实现模态框封装:
<!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>面向对象封装消息提示</title>
<style>
.modal {
width: 300px;
min-height: 100px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 4px;
position: fixed;
z-index: 999;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
background-color: #fff;
}
.modal .header {
line-height: 40px;
padding: 0 10px;
position: relative;
font-size: 20px;
}
.modal .header i {
font-style: normal;
color: #999;
position: absolute;
right: 15px;
top: -2px;
cursor: pointer;
}
.modal .body {
text-align: center;
padding: 10px;
}
.modal .footer {
display: flex;
justify-content: flex-end;
padding: 10px;
}
.modal .footer a {
padding: 3px 8px;
background: #ccc;
text-decoration: none;
color: #fff;
border-radius: 2px;
margin-right: 10px;
font-size: 14px;
}
.modal .footer a.submit {
background-color: #369;
}
</style>
</head>
<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>
//构造函数封装——模态框
function Modal(title = '', message = '') {
//创建div标签
this.modalBox = document.createElement('div')
//给div标签添加类名为modal
this.modalBox.className = 'modal'
//modal盒子内部填充2个div标签并且修改文字内容
this.modalBox.innerHTML = `
<div class="header">${title} <i>x</i></div>
<div class="body">${message}</div>
`
console.log(this.modalBox)
}
Modal.prototype.open = function () {
const box = document.querySelector('.modal')
//防止创建多个模态框,使其有则移除,没有就继续执行
box && box.remove()
document.body.append(this.modalBox)
//x要在模态框创建完成后才能点击关闭
this.modalBox.querySelector('i').addEventListener('click', () => {
this.close()
})
}
Modal.prototype.close = function () {
this.modalBox.remove()
}
document.querySelector('#delete').addEventListener('click', () => {
const del = new Modal('温馨提示', '您没有权限删除操作')
del.open()
})
document.querySelector('#login').addEventListener('click', () => {
const login = new Modal('友情提示', '您没有注册呢?')
login.open()
})
</script>
</body>
</html>