JS原型和原型链
1:使用class实现继承
比如说我们定义一个类,给你一个构造函数,在初始化的时候通过名字和分数对这个类进行初始化
我们也可以定义一个自我介绍的方法
class Student {
constructor(name,score) {
this.name = name;
this.score = score;
}
introduse(){
console.log(`我是${this.name},我考了${this.score}分`)
}
}
const std = new Student("ldz", 150)
console.log("student",std)
std.introduse()
比如这个时候我们再定义一个老师类
class Teacher {
constructor(name,subject) {
this.name = name;
this.subject = subject;
}
introduse(){
console.log(`我是${this.name},我考了${this.subject}分`)
}
}
const teacher = new Teacher("addam", "js")
console.log("teacher",teacher)
std.introduse()
这个时候这两个类都有name这个属性,我们就可以定义一个父类Person,我们定义Person有name属性,Person有个drink的喝水方法,然后学生类和老师类均继承Person
class Person {
constructor(name) {
this.name = name;
}
drink(){
console.log(`我是人,我要喝水`)
}
}
class Student extends Person{
constructor(name,score) {
super(name);
this.score = score;
}
introduse(){
console.log(`我是${this.name},我考了${this.score}分`)
}
}
const std = new Student("ldz", 150)
console.log("student",std)
std.introduse()
std.drink()
class Teacher extends Person{
constructor(name,subject) {
super(name);
this.subject = subject;
}
introduse(){
console.log(`我是${this.name},我考了${this.subject}分`)
}
}
const teacher = new Teacher("ldz", "js")
console.log("teacher",teacher)
teacher.introduse()
teacher.drink()
从上面代码可以看出,继承之后就可以直接使用父类的方法了,但是如果要在初始化时也初始化父类的某一变量,那么就需要使用super()关键字。
2:js原型
首先可以看到我们刚才console.log(“student”,std)输出的std只有name和score两个属性,那为什么会存在std.introduse()呢。
这个时候就不能忽略底下的__prito__
,这个就被称为隐式原型。这个__prito__
也是一个对象,他内部就有introduse。
那我们可以输出一下Student.peototype,可以发现输出也是两个方法,而且Student.peototype === student.__proto __
。
此时 student.__proto __ ===Student.peototype
其实就是隐式原型等于显示原型。然后当我们在一个对象上查找属性和方法的时候,查不到就回去这个函数的隐式原型上查找。
3:JS原型链
先写一个teacher方法
class Person {
constructor(name) {
this.name = name;
}
drink(){
console.log(`我是人,我要喝水`)
}
}
class Teacher extends Person{
constructor(name,subject) {
super(name);
this.subject = subject;
}
teach(){
console.log(`我是${this.name},我教${this.subject}课程`)
}
}
const teacher = new Teacher("ldz", "js")
console.log("teacher",teacher)
teacher.teach()
teacher.drink()
这个时候teacher构造成功之后执行了两个方法,一个是teacher.teach(),这个是在teach存在于teacher对象的隐式原型,也就是Teacher类的显示原型,但是那teacher.drink()中的drink又是哪来的呢
teacher.drink()是teacher继承Person之后,Person里面的方法,我们可以看到Teacher类中的Teacher.peototype中还有一个__proto__
,点开之后这个__proto__
里面就存在drink变量。
Teacher类继承于Person,所以其实Teacher的隐式原型Teacher.peototype的__proto__
就指向于Person的显示原型Person.peototype。当drink在Teacher类找不到时,就会去Teacher的显示原型(teacher的隐式原型)中去找,要是还找不到就会去Teacher的显示原型的隐式原型中去找,层层找下去这个链就是原型链。
当我们访问一个对象的属性和方法时,他首先会从自身去找,如果找不到就从他的原型去找,如果还是找不到,就从他原型的原型去找,这样就形成了一个链式结构,这个结构就叫原型链
那怎么检查一个属性和方法是不是对象自身的属性和方法呢,这里面有一个方法,对象.hasOwnProperty("属性或方法名")
class Person {
constructor(name) {
this.name = name;
}
drink(){
console.log(`我是人,我要喝水`)
}
}
class Teacher extends Person{
constructor(name,subject) {
super(name);
this.subject = subject;
}
teach(){
console.log(`我是${this.name},我教${this.subject}课程`)
}
}
const teacher = new Teacher("ldz", "js")
console.log("teacher.name",teacher.hasOwnProperty("name"))
console.log("teacher.teach",teacher.hasOwnProperty("teach"))
那么这个hasOwnProperty又是哪里来的呢,这个是Person继承的Object类里面的,这个里面的隐式原型就是null,也就是说如果teacher一个方法,theacher本身没有,teacher的隐式原型(teacher.__proto __ \ Teacher
)没有,teacher的隐式原型的隐式原型(peototype.peototype \ Person)没有,teacher的隐式原型的隐式原型的隐式原型(Person.peototype \ Object)没有,那就真的没有了,因为teacher的隐式原型的隐式原型的隐式原型的隐式原型(Object.peototype )为null,找不下去了。
4:使用instanceof做类型判断
众所周知,typeof可以对数据做类型判断,但是还是有很多数据类型无法区分开来。
const object = {}
const array = []
console.log("object:\t",typeof object)
console.log("array:\t",typeof array)
上面一个对象,一个数组,但是最后函数输出如下图
这个时候就要用instanceof做类型判断
const object = {}
const array = []
console.log("object:\t",typeof object)
console.log("array:\t",typeof array)
const object_res = object instanceof Array;
const array_res = array instanceof Array;
console.log("object:\t",object_res)
console.log("array:\t",array_res)