# 原型与原型链
# 原型
我们在此先定义一个Student类
这个类有两个属性,name和subject
同时还有一个方法learn()
class Student{
constructor (name, subject) {
this.name = name
this.subject = subject
}
learn () {
console.log(this.name + '正在学习' + this.subject)
}
}
接下来我们构建一个Student类的实例—student1
const student1 = new Student('张三', '犯罪心理学')
student1.learn()
console.log(student1)
然后我们看一下输出结果
张三正在学习犯罪心理学
Student{name: "张三", subject: "犯罪心理学"}
展开Student{...}这个object,会发现,learn()方法并不在其中,而是以下三个内容
name、subject、_proto_
那么,learn()方法从何而来的?便是在 _proto_ 中
_proto_这个属性,被称为 student1 这个对象的 隐式原型
当在对象之中找不到一个属性或方法时,将会到隐式原型中寻找,如果隐式原型中能够找到该属性或方法,则进行访问并调用。
以上诉例子来说,student1调用learn()方法,在当前对象中没法找到该方法,便在student1.__proto__中寻找,寻找到了,访问并调用
那么,我们的student1这个对象,是Student类构建出来的实例,而我们在控制台输入Student.时,会发现,Student类有一个属性,是prototype
Student.prototype
得到的是一个对象,内容是否有点似曾相识?
我们再输出一下student1._proto_
得到的是什么?是否输出的内容和前者一样?
我们不妨大胆猜测一下,输出的两个对象就是同个东西
Student.prototype === student1.__proto__
结果是什么?
true
因此我们可以得到:
student1上的_proto_,指向的的就是Student.prototype这个对象,这个对象上会有一个方法learn()
而在我们的Student类上,它有一个属性prototype,这个属性指向的也是Student.prototype这个对象。
是同一个对象。
我们每一个对象都会有一个原型,该原型我们一般称之为隐式原型
隐式原型 将会指向 构建出这个对象的类 的 显式原型
因此,当我们在一个对象中寻找一个方法或属性时,将会往该对象的隐式原型上查询
# 原型链
我们重新定义一下我们的Student类,每个人都有一个名字,学生都有名字,除了学生其他人也有名字,因此Student这个类,是可以继承于Person类的,Person类中定义了name属性,同时也定义了eat()这个方法
class Person{
constructor(name){
this.name = name
}
eat () {
console.log(this.name + '正在吃饭')
}
}
定义Student类,继承于Person类
class Student extends Person {
constructor (name,subject) {
super(name)
this.subject = subject
}
learn () {
console.log(this.name + '正在学习' + this.subject)
}
}
构建Student类的实例student1
const student1 = new Student('张三', '犯罪心理学')
student1.eat()
student1.learn()
console.log(student1)
查看输出的结果
按照我们上述的内容,我们能够很清楚的得知,student1.learn()方法在输出的Student{..}中的__proto__这个对象中
但是,eat()方法并没有在其中,但我们却依旧可以执行
这是因为我们的Student类继承于Person类,eat()方法是定义在Person类之中的
我们也可以发现,输出的Student{..}中的__proto__对象之中,还有一个__proto__,而eat()方法就在其中
即:
- student1.__proto__ === Student.prototype
- student1.__proto__.__proto__ === Person.prototype = Student.prototype.__proto__
这样子便形成了一个链,这个链称之为原型链,student1通过原型链,找到了eat()这个方法并执行。
当我们访问一个对象的属性或方法时,首先会在这个对象内进行寻找,如果寻找无果,便会在该对象的原型内进行寻找,如果该对象的原型内寻找无果,则会在该对象的原型的原型内进行寻找,形成链式的结构
如何判断一个属性或方法是该对象本身的?
console.log(student1.hasOwnProperty('name'))
// true
console.log(student1.hasOwnProperty('eat'))
// false
// object.hasOwnProperty()
但是,hasOwnProperty()这个方法,又是从哪里来的?
我们不妨挨个一个个点开__proto__
我们会发现,最后的__proto__中,constructor的名字是 Object()
而hasOwnProperty()这个方法也在这里
及原型链的最上级,是Object.prototype
那么这里又有一个疑问了:Object.prototype也是一个对象,它的隐式原型又是什么?
答案是 null
# instanceof
instanceof运算符,用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
console.log(student1 instanceof Student)
// true
console.log(student1 instanceof Person)
// true
console.log(student1 instanceof Object)
// true
console.log(student1 instanceof Array)
// false
← 声明提升(Hoisting) 原型式的继承 →