写在前面: 这篇文章主要是根据自己的理解分享了什么是原型和原型链
- 原型, 原型链, 原型对象, 实例, 的定义
- 原型对象图示
- 如何获取原型对象
原型, 原型链, 原型对象的定义
1. 什么是实例,如何创建实例
实例就是通过 构造函数 / 或者其他方法 生成的一个对象
例如:
//1- 通过字面量方式实例化对象
let a = {
name: '张三'
}
//2- 通过 new Object 来实例化一个对象 b就是一个实例
let b = new Object()//b = {}
//3- 通过构造函数来实例化一个对象 p也是一个实例
function Person (name) {
this.name = name
}
let p = new Person('张三')
当我们打印这些实例的时候,会发现有一个 __ proto __ (双下划线)的属性,它的类型是一个对象(引用类型),b.__ proto __里面就存放着这个实例的原型对象
在解释其他内容之前,先抛出一个小例子来说明这些内容
//首先我写了一个人的构造函数(Person)
function Person(name){
this.name = name
}
//从上面可以知道 可以通过 new Person 来实例化一个对象
let p1 = new Person('张三')
//根据下面图1 打印p1 可以看出有一个 Person 的对象
//有一个属性叫做 name ,值为 '张三'
//它的原型对象(我给他取一个名字叫做 原型对象1)里面有一个 构造器 function Person(name)
//它的原型对象里面还有一个原型对象 (我给他取一个名字叫做 原型对象2)
图1 打印p1
2. 什么是原型对象
原型对象是由构造函数的prototype属性和这个构造函数创建的实例对象的__proto__属性共同指向的一个原型链上的对象
原型对象也是一个对象, 所以它也会有自己的原型对象(除非这个已经是顶层对象 Object 了===>Object 没有原型对象(指向 null))
如上图: p1.__ proto __ 指向的就是原型对象
3. 原型链
原型链是原型以及它的原型对象构成的链条 如上图 的原型链就是:
p1 -> 原型对象1 ->原型对象2
这个链条就叫做原型链
原型链图示
如何获取原型对象
通过实例化后的对象: p1.__ proto __
通过构造器: Person.prototype
给原型对象添加属性会怎样?
//分别用这两种方法给原型对象添加属性
p1.__ proto __.age = 18
Person.prototype.sex = '男'
console.log('p1.age',p1.age)//18
console.log('p1.sex',p1.sex)//男
添加后重新打印 person
在相关属性(方法)时,首先去找自身的属性和方法, 若没有找到, 就去找上层的原型对象里面的属性和方法(如下个例子,为最顶层的原型对象添加一个 desc 属性), 若逐层向上直到最顶层都还没有找到的话则不存在该属性或者方法(如果是打印: 则为 undefined )
Object.prototype.desc = 'object 的原型对象'
console.log(p1.desc) //打印结果 object 的原型对象
console.log(p1.c) //打印结果 undefined (在原型链中并不存在这个属性)
给原型对象赋值会怎么样?
//给顶层的 Object 的原型对象添加属性
Object.prototype.sex = 'object 的原型对象的sex'
//若此时想要得到 p1.sex
console.log(p1.sex) //打印结果 男 =====就近原则
//给 p1 的原型对象赋值(空对象)
p1.__proto__ = {}
console.log(p1.sex) //打印结果 object的原型对象的sex,因为 p1 的直接原型对象已经找不到了 sex 了
给原型对象赋一个不是对象的值会怎样?
我最先的想法是,如果原型对象已经不是一个对象了的话,这个原型链还会存在吗?
于是 修改代码
p1.__proto__ = 1
console.log(p1.name)//打印结果 张三
console.log(p1.age)//打印结果 undefined
console.log(p1.sex)//打印结果 object 的原型对象的sex(这个是在 p1 直接原型对象上的)
console.log(p1.desc)//打印结果 object 的原型对象
所以,总结一下,原型链并不会断裂,只会往顶层找,找不到就 undefined
//分享的所有代码
console.log('------------构造函数-----------------')
function Person(name) {
this.name = name
}
let p1 = new Person('张三')
console.log(p1)
console.log('-----------给 p1 的原型对象添加属性------------------')
p1.__proto__.age = 18
Person.prototype.sex = '男'
console.log(p1)
console.log('p1.age',p1.age)//打印结果 18
console.log('p1.sex',p1.sex)//打印结果 男
console.log('-----------给顶层(Object)的原型对象添加属性------------------')
Object.prototype.desc = 'object 的原型对象'
Object.prototype.sex = 'object 的原型对象的sex'
console.log(p1.desc)//打印结果 object 的原型对象
console.log('-----------给 p1 的原型对象赋值(空对象)------------------')
p1.__proto__ = {}
console.log(p1.sex)//打印结果 object 的原型对象的sex
console.log('-------------给 p1 的原型对象赋值(非对象)----------------')
p1.__proto__ = 1
console.log(p1.name)//张三
console.log(p1.age)//undefined
console.log(p1.sex)//object 的原型对象的sex
console.log(p1.desc)//object 的原型对象
end
参考资源:回顾——原型对象、原型链、构造函数、实例对象之间的关系