类的创建
js中创建一个类很容易,如下所示:
<script>
class Person {
}
let p1 = new Person();
let p2 = new Person();
console.log(p1);
console.log(p2);
</script>
以上创建一个类,并且创建它的实例p1 和p2,输出可以看到输出两个Person实例
但是,我们实例两个对象却无法区分(输出 都一样啊),所以我们需要对类进行传参,让每一个实例对象都有自己的属性
<script>
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
}
let p1 = new Person('小明',18);
let p2 = new Person('小红',17);
console.log(p1);
console.log(p2);
</script>
同样我们可以在类中定义一些方法,让实例区调用
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say() {
console.log(`大家好,我是${this.name},我今年${this.age}了`);
}
}
let p1 = new Person('小明',18);
let p2 = new Person('小红',17);
console.log(p1);
console.log(p2);
p1.say();
p2.say();
我们刚才创建了一个类Persion,并且实例了它的对象p1,类和实例之间还有一层关系,那就是原型,原型也是一个对象,它里面有一些属性和方法可以被类和实例继承。
类里面有一个属性,叫做prototype,它可以指向这个原型,同样,类的实例也有一个属性,叫做 proto,它也可以指向这个原型,而原型有一个属性,叫做constructor,它可以指向类,这样,他们三个的关系可以用图来表示。
同样,从浏览器中我们也能看出来这种关系,比如我们 刚才实例了p1,并把p1输出,那么从刚才那张图中我们就可以从p1中去找到原型,从原型中找到类
可以看到,输出的实例p1中有一个属性_proto_,它指向一个对象,这个对象就是 原型,我们展开原型
可以看到,展开原型,发现原型里面有一个constructor属性,它指向Person类,我们展开类
可以看到类里面有个prototype属性,它指向一个对象,打开对象发现还是 之前那个原型,因此,类,实例对象,原型之间的关系就可以解释的通了。还有一个细节,p1通过_proto_找到原型链的时候,原型链上有一个方法say(),而接着找到类的时候,类中却没有say()方法,这就验证类我们之前的话,类的一些方法放在了原型中,实例可以从原型中继承方法来使用。
下面来看 类的继承
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say() {
console.log(`大家好,我是${this.name},我今年${this.age}了`);
}
}
class Student extends Person{
}
let s1 = new Student('张三',13)
console.log(s1)
s1.say()
这里创建了一个Studengt类,它继承了Prson,并且实例了一个对象s1 ,调用了say()方法,我们知道,Student里面没有say()方法,说吗Student原型里面 也没有say()方法,那么他是怎么找到say()方法并调用呢?我们输出s1,发现了这样一层关系
即Student原型上如果没有找到所需函数,原型会通过_proto_找到继承的父类的原型,在父类原型上找,这就构成了原型链。
如果我们在Student上重写方法
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say() {
console.log(`大家好,我是${this.name},我今年${this.age}了`);
}
}
class Student extends Person{
constructor(name,age,hobby){
super(name,age)
this.hobby = hobby
}
say() {
console.log(`我的爱好是${this.hobby}`)
}
}
let s1 = new Student('张三',13,'画画')
console.log(s1)
s1.say()
那么这里输出的say() 方法则是在Student上定义的方法,原因也可以在原型链上解释
当student的实例s1首先会在其自己的原型上查找say(),如果没有找到,则通过_proto_去上层原型上查找,如果找到,则不会再去上层原型查找
还有一个细节,我们知道,js中有个Object类,它是所有对象的父类,那么Person的原型肯定可以通过_proto_,找到Object的原型