this在类中的表现
类
类的本质还是一个函数
先来写一个简单的类,通过new出来的实例是一个对象
class Test {
}
const t = new Test()
console.log(t); // Test {}
我们在类中先添加一个静态方法
class Test {
say(){
console.log(this); // Test {}
}
}
const t = new Test()
t.say()
结果就是类里面的方法指向的是这个类实例化出来的对象
类里面还有一个构造器,在类的构造器中也定义一个say方法
class Test {
constructor(){
this.say = function(){
console.log("非静态方法" + this);
}
}
say(){
console.log("静态方法" + this);
}
}
const t = new Test()
t.say() // 非静态方法[object Object]
打印的结果表明,t.say()执行的是构造器里面的say方法。因为在类的构造器中添加的方法叫做非静态方法,在类实例化的时候会生成一个this指向一个空对象,构造器的非静态方法以及添加的属性都会添加到这个空对象中;而静态方法就是不是在构造器中定义的方法在类定义的时候就放到Test.prototype这个对象中去了
即
new Test() -> this -> {
say(){
console.log("静态方法" + this);
}
}
class Test { constructor () {...} say () {...}}
->此时 Test.prototype = {
say (){
console.log("静态方法" + this);
}
}
而类在new的时候,生成了this的新的指向,指向了一个空对象{},这个空对象是有自己的 __ proto __ 属性,这个属性又指向了Test.prototype,就是原型链的一个过程
即
new 产生的this = {
__ proto __ : Test.prototype
}
就是类的实例在执行say的时候,先在自己this指向的这个对象中找,如果有就执行,如果没有say方法就顺着 __ proto __ 指向的Test.prototype对象中找,如果有就执行,没有就继续沿着 __ proto __ 想上找,直到 Object.prototype停止
一般情况下,对象都有 __ proto __ 这个属性,指向构造他的类或者构造函数的原型属性,除非是通过方法修改了对象的原型,如通过Object.create(null)将创建的对象的原型指定为null
Snipaste_2021-06-26_20-21-27.png
继承
定义一个父类,一个子类继承父类,各定义一个方法,子类的方法中调用父类的方法,子类能否执行父类方法,子类的this指向哪?
class Father {
shop () {
console.log('go shopping');
}
}
class Son extends Father {
study () {
console.log(this); // Son {}
this.shop() // go shopping
}
}
const s1 = new Son()
s1.study()
子类可以调用父类方法,this指向的实例化的对象。而且Son{}上面只有 __ proto __ ,指向了class Father,而且shop方法也不是在Father对象里面,而是在Father的原型上
Snipaste_2021-06-26_20-37-19.png
所以s1.study()执行顺序就是先访问Son原型上面的study方法,然后访问Father原型属性上面的shop方法,说白了就是沿着原型链向上找。现在在Father的构造器的this上添加一个age属性
class Father {
constructor(){
this.age = 44
}
shop () {
console.log('go shopping');
}
}
Son的实例对象是访问不到的,基类在继承的过程中是没有this绑定的,并没有对Father进行实例化。实际上Son的this是继承了Father的原型而来的,指向还是Son的实例。那现在在子类的构造器的this上添加一个属性
class Son extends Father {
constructor(){
this.name = 'zhang'
}
study () {
console.log(this);
this.shop()
}
}
一执行就会报错
ReferenceError: Must call super constructor in derived
class before accessing 'this' or returning from derived constructor
意思就是在访问派生类就是子类在构造器中访问this之前要调用supper。不论Father有无constructor,子类要访问this,都必须调用supper
class Father {
constructor(){
this.age = 44
}
shop () {
console.log('go shopping');
}
}
class Son extends Father {
constructor(){
super()
this.name = 'zhang'
}
study () {
console.log(this); // Son { age: 44, name: 'zhang' }
this.shop() // go shopping
}
}
const s1 = new Son()
s1.study()
此时就不报错了,而且this中也有了两个属性,一个是父类的age,一个是我们自己添加的name,在访问this.age就有东西了
class Son extends Father {
constructor(){
super()
this.name = 'zhang'
console.log(this.age); // 44
}
...
}
那么supper在这里做了什么呢??
首先时调用了父类的constructor,生成了this绑定,通过上面的stydy方法打印出的this:Son { age: 44, name: 'zhang' }可以看出Father内部的this指向了Son的实例,就是相当于当前this执行了new
Father,生成了一个对象{},然后父类构造器的属性也会添加到这个{}中去 -> {age: 44},然后我们在Son的构造器中添加了name,所以this -> { age: 44, name: 'zhang' }
如果调换 super(); this.name = 'zhang'的位置
class Son extends Father {
constructor(){
this.name = 'zhang'
super()
}
...
}
同样会报那个错误
ReferenceError: Must call super constructor in derived class
before accessing 'this' or returning from derived constructor
在访问this之前必须先supper,在调用supper之前不能访问this的原因就是你的子类在继承之后,就是为了访问到父类的非静态属性和方法,你先对this进行了操作,然后supper之后,生成了新的this指向对象,那原来的该怎么办,通过supper向父类传值的,子类再访问这个值,这才是类的意义所在。
网友评论