Pink老师JS进阶DAY3学习记录-原型
一. 原型
1. 原型
一个对象,称prototype为原型对象。
2. 作用
共享方法,把不变的方法,直接定义在prototype对象上
// 公共的属性写到构造函数里
function Star(uname) {
this.uname = uname
}
// 公共的方法写到原型对象上
Star.prototype.sing = function () {
console.log('唱歌')
}
const ldh = new Star('刘德华')
ldh.sing()
3. 注意
构造函数和原型对象的this都指向实例对象,前者不用说了,后者从ldh.sing()
就可以看出来,因为this指向函数的调用者
4. 小小案例(数组拓展方法)
自定义拓展方法写道prototype对象上,这里我们实现,数组最大值,最小值,求和方法。
const arr = [1, 2, 3]
Array.prototype.max = function () {
return Math.max(...this)
}
Array.prototype.min = function () {
return Math.min(...this)
}
Array.prototype.sum = function () {
return this.reduce((prev, item) => prev + item , 0)
}
console.log(arr.max()) // 3
console.log([2, 5, 9].max()) // 9
console.log(arr.min()) // 1
console.log([11, 21, 31].sum()) // 63
5. constructor属性
每个原型对象里面都有个constructor 属性,它指向原型的构造函数,也就是它的爹
有一个问题,如果给一个原型对象里追加多个方法,它就不再指向当前构造函数。解决方法是在修改后的原型对象中添加一个constructor指向原来的构造函数。
function Star() {
}
Star.prototype = {
// 重新指回创造这个原型对象的 构造函数
constructor: Star,
sing: function () {
console.log('唱歌')
},
dance: function () {
console.log('跳舞')
},
}
console.log(Star.prototype)
6. 对象原型(实例对象为什么能访问到原型对象)
就是实例对象的一个非标准属性,__proto__
,看到[[prototype]]
也是它。表示实例对象指向的那个原型对象
构造函数,实例对象,原型对象的指向关系如下:
(对象原型里也有一个constructor属性指向构造函数)
console.log(ldh.__proto__ === Star.protoType) // true
console.log(ldh.__proto__.constructor === Star) // true
7. 原型继承(重要)
<script>
// 构造函数 new 出来的对象 结构一样,但是对象不一样
function Person() {
this.eyes = 2
this.head = 1
}
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)
// 男人 构造函数 继承 想要 继承 Person
function Man() {
}
// 通过 原型继承 Person
Man.prototype = new Person()
Man.prototype.constructor = Man
const pink = new Man()
console.log(pink)
</script>
注意:
- 原型继承的时候应该是new出来的对象,不然继承的是同一个对象,这样才不会对其他继承的对象产生影响。
- 可以通过原型再给对象添加方法。
- 注意要指向原来的构造函数。
8. 原型链
注意:只要是对象,就有__proto__
,指向原型对象,只要是原型对象,就有constructor
,指向构造函数
原型链图:
原型链查找规则:
为什么arr.map()
能用
因为arr是一个数组,也是一个对象,原本对象没有map方法,就从它的原型Array.prototype
来找,有,就可以用
关于instanceof
运算符
function Person() {
}
const ldh = new Person()
console.log(ldh instanceof Person) // true
console.log(ldh instanceof Object) // true
console.log(ldh instanceof Array) // false
console.log([1, 2, 3] instanceof Array) // true
console.log(Array instanceof Object) // true
二. 案例(模态框,面向对象)
需求:
点击按钮,模态框显示提示信息,可以点击X关闭模态框。
打开模态框和关闭模态框都是公共的方法,可以写到原型里,创建模态框的提示和提示具体信息是公共属性,还有盒子也是公共的,可以写到构造函数里。
代码:
// 1. 模态框的构造函数
function Modal(title = '', message = '') {
// 公共的属性部分
this.title = title
this.message = message
// 盒子也是公共的
this.modalBox = document.createElement('div')
this.modalBox.className = 'modal'
this.modalBox.innerHTML = `
<div class="header">${this.title} <i>x</i></div>
<div class="body">${this.message}</div>
`
}
// 2. 打开方法 挂载到模态框的构造函数的原型身上
Modal.prototype.open = function () {
// 判断是否有模态框,有才执行,不然可以有很多模态框
if (!document.querySelector('.modal')) {
// 把刚才创建的盒子 modalBox 渲染到 页面中
document.body.appendChild(this.modalBox)
// 获取 x 调用关闭方法
this.modalBox.querySelector('i').addEventListener('click', () => {
// 要是普通函数的话,这里的this指向i
// 箭头函数没有this 上一级作用域的this
// 这个this 指向实例对象 m
this.close()
})
}
}
// 3. 关闭方法 挂载 到模态框的构造函数原型身上
Modal.prototype.close = function () {
document.body.removeChild(this.modalBox)
}
// 4. 按钮点击
document.querySelector('#delete').addEventListener('click', () => {
const m = new Modal('温馨提示', '您没有权限删除')
// 调用 打开方法
m.open()
})
// 5. 按钮点击
document.querySelector('#login').addEventListener('click', () => {
const m = new Modal('友情提示', '您还么有注册账号')
// 调用 打开方法
m.open()
})