# 原型与原型链

# 原型

我们在此先定义一个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()方法就在其中

即:

  1. student1.__proto__ === Student.prototype
  2. 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
更新时间: 6/21/2021, 10:16:30 PM