宽屏
1. 对象原型
对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在。

注意:
__proto__ 是JS非标准属性
[[prototype]]和__proto__意义相同
用来表明当前实例对象指向哪个原型对象prototype
__proto__对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数
2. 原型继承
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript 中大多是借助原型对象实现继承的特性。
龙生龙、凤生凤、老鼠的儿子会打洞描述的正是继承的含义。
我们来看个代码:
function Man() {
this.head = 1
this.eyes = 2
this.legs = 2
this.say = function() {}
this.eat = function() {}
}
const man = new Man()function Woman() {
this.head = 1
this.eyes = 2
this.legs = 2
this.say = function() {}
this.eat = function() {}
this.baby = function() {}
}
const woman = new Woman()1. 封装-抽取公共部分
把男人和女人公共的部分抽取出来放到人类里面
// 人类
const People = {
head: 1,
eyes: 2,
legs: 2,
say: function() {},
eat: function() {}
}
// 男人
function Man() {
}
// 女人
function Woman() {
this.baby = function() {}
}2. 继承-让男人和女人都能继承人类的一些属性和方法
把男人女人公共的属性和方法抽取出来 People
然后赋值给Man的原型对象,可以共享这些属性和方法
注意让constructor指回Man这个构造函数
// 人类 公共的属性和方法
const People = {
head: 1,
eyes: 2,
legs: 2,
say: function() {},
eat: function() {}
}
// 男人
function Man() {
}
// 把公共的属性方法给原型,这样就可以共享了
Man.prototype = People
// 注意让原型里面的constructor重新指回Man找自己的爸爸
Man.prototype.constructor = Man
const kun = new Man()
console.log(kun)
3. 问题:
如果我们给男人添加了一个吸烟的方法,发现女人自动也添加这个方法
// 人类 公共的属性和方法
const People = {
head: 1,
eyes: 2,
legs: 2,
say: function() {},
eat: function() {}
}
// 男人
function Man() {
}
// 把公共的属性方法给原型,这样就可以共享了
Man.prototype = People
// 注意让原型里面的constructor重新指回Man找自己的爸爸
Man.prototype.constructor = Man
// 抽烟
Man.prototype.smoking = function() {}
const kun = new Man()
console.log(kun)
// 女人
function Woman() {
this.baby = function() {}
}
// 把公共的属性方法给原型,这样就可以共享了
Woman.prototype = People
// 注意让原型里面的constructor重新指回Woman找自己的爸爸
Woman.prototype.constructor = Woman
const ji = new Woman()
console.log(ji)
原因
男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响

4. 解决:
需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
答案:构造函数
new 每次都会创建一个新的对象
// 人类 公共的属性和方法
function People() {
this.head = 1
this.eyes = 2
this.legs = 2
this.say = function() {}
this.eat = function() {}
}
// 男人
function Man() {
}
// 把公共的属性方法给原型,这样就可以共享了
Man.prototype = new People()
// 注意让原型里面的constructor重新指回Man找自己的爸爸
Man.prototype.constructor = Man
// 抽烟
Man.prototype.smoking = function() {}
const kun = new Man()
console.log(kun)
// 女人
function Woman() {
this.baby = function() {}
}
// 把公共的属性方法给原型,这样就可以共享了
Woman.prototype = new People()
// 注意让原型里面的constructor重新指回Woman找自己的爸爸
Woman.prototype.constructor = Woman
const ji = new Woman()
console.log(ji)
思路
真正做这个案例,我们的思路应该是先考虑大的,后考虑小的
1. 人类共有的属性和方法有那些,然后做个构造函数,进行封装,一般公共属性写到构造函数内部,公共方法,挂载到构造函数原型身上。
2. 男人继承人类的属性和方法,之后创建自己独有的属性和方法
3. 女人同理
3. 原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

原型链-查找规则
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object 为止(null)
⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上