一、原型对象
(一)什么是原型
原型本质上是一个对象,也称为Prototype为原型对象
(二)原型作用
共享方法
可以把那些不变的方法,直接定义在prototype对象身上
例如:将公共的sing方法写在Star方法的原型对象身上 节约内存
// 构造函数 公共的属性和方法 封装到 Star 构造函数里面了
// 1.公共的属性写到 构造函数里面
function Star(uname, age) {
this.uname = uname
this.age = age
// this.sing = function () {
// console.log('唱歌')
// }
}
// 2. 公共的方法写到原型对象身上 节约了内存
Star.prototype.sing = function () {
// 原型对象里面的函数this指向的还是 实例对象
console.log('唱歌')
}
const ldh = new Star('刘德华', 55)
const zxy = new Star('张学友', 58)
ldh.sing() //调用
zxy.sing() //调用
// console.log(ldh === zxy) // false
console.log(ldh.sing === zxy.sing)
(三)constructor属性
(1)constructor作用
指回该原型对象的构造函数。每个原型对象里面都有个constructor 属性(constructor 构造函数)该属性指向该原型对象的构造函数。
(2)constructor应用场景
如果有多个对象的方法,我们可以给原型对象采取对象形式赋值.
但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了
function Star() {
}
// console.log(Star.prototype)
Star.prototype = {
sing: function () {
console.log('唱歌')
},
dance: function () {
console.log('跳舞')
},
}
console.log(Star.prototype)
输出结果:
此时,我们可以在修改后的原型对象中,添加一个 constructor 来指向原来的构造函数。
function Star() {
}
// console.log(Star.prototype)
Star.prototype = {
// 从新指回创造这个原型对象的 构造函数
constructor: Star,
sing: function () {
console.log('唱歌')
},
dance: function () {
console.log('跳舞')
},
}
console.log(Star.prototype)
输出结果:
二、对象原型
(一)什么是对象原型
对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在。
__proto__对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数。
(二)对象原型、原型对象 、构造函数的关系
三、原型继承
(一)封装——抽取公共部分
(二)继承
(三)存在的问题
如果给Man添加smoking方法,会发现在women里也被自动添加了这个方法
原因:男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响
解决办法:
将people写成构造函数形式,因为构造函数每次new的对象只是结构一样,但是对象不一样,只需要将new People()替换刚才的固定对象
完整写法:
四、原型链
(一)什么是原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链。
(二)原型链查找规则
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)
如果还没有就查找原型对象的原型(Object的原型对象)
依此类推一直找到 Object 为止(null)
__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
可以使用instanceof运算符检测构造函数的prototype属性是否出现在某个实例对象的原型链上