有如下代码:
class Parent { constructor() { console.log('parent constructor', this.name) this.init() this.logNum = this.logNum.bind(this) } name = (() => { console.log('Parent name init') return 'Parent' })() num = -1 init() { console.log('parent init', this.name) } logNum() {}}class Child extends Parent { constructor() { console.log('Child constructor') super() console.log('super exec finish', this.num) } name = 'Child' num = (() => { console.log('Child num init') return 99 })() init() { console.log('Child init', this.name) super.init() this.num = 10 } logNum() { console.log(this.num) }}const { logNum } = new Child()logNum()
打印结果:
Child constructorParent name init parent constructor ParentChild init Parent parent init Parent Child num init super exec finish 99 99
1、在实例化Child时,Parent.constructor中的name为什么是'Parent'?Child.constructor
中调用super
,内部this
指向为Child
,所以不应该是'Child'吗?
2、诸如x = 'a'的实例属性是什么时候完成初始化的?Child.constructor
中调用super
时,可以看到打印了'Parent name init'
,说明实例属性是在构造器方法之前就初始化了吧,那为什么Child.num
是在super
调用结束后才初始化?
代码可以转化为下列的形式
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }class Parent { constructor() { _defineProperty(this, "name", (() => { console.log('Parent name init'); return 'Parent'; })()); _defineProperty(this, "num", -1); console.log('parent constructor', this.name); this.init(); this.logNum = this.logNum.bind(this); } init() { console.log('parent init', this.name); } logNum() {}}class Child extends Parent { constructor() { console.log('Child constructor'); super(); _defineProperty(this, "name", 'Child'); _defineProperty(this, "num", (() => { console.log('Child num init'); return 99; })()); console.log('super exec finish', this.num); } init() { console.log('Child init', this.name); super.init(); this.num = 10; } logNum() { console.log(this.num); }}const { logNum} = new Child();
1、创建子类实例对象,会在子类构造函数中 super
执行完之后才会把父类的实例属性和方法放到子类的实例对象上,所以在 super
中执行 this.name
时,子类的属性和方法还没有绑定到 this
上面去,此时会去父类查找同名的属性。
2、需要注意的是 super
代表的是父类的构造函数,但 super
内部的 this
代表子类的实例,而不是父类的实例。
这篇文章可能对你的问题能有更好的理解 Class的继承
导致你产生这个疑问的原因是你对类成员
的初始化时机
理解不准确,你可以把这段代码用babel做一个语法降级就能看出
constructor
中,super()
执行完成之后进行的,也就是说,虽然 super()
中 this 指向是 Child
的实例,但其成员都还没有初始化,所以访问到的值还是 Parent
赋的默认值当实例化Child时,会首先执行父类Parent的构造函数,然后再执行子类Child的构造函数。
在Parent.constructor方法中打断点如下图所示:
从上图Scope栏中的Local作用域可知,虽然this值指向Child,但是其内部的name属性值是“Parent”
原因是类字段初始化发生在构造函数执行之前。当 Parent 的构造函数被调用时,类字段的初始化,也就是表达式赋值
name = (() => { console.log('Parent name init') return 'Parent'})()
已经发生了。
不妨在Parent中增加如下代码:
parentName = "parentName"init() { console.log('parent init', this.name) //结果输出parent init Parent console.log("test: ", this.parentName) //结果输出test: parentName}
实际上还是先对类字段进行初始化,然后再调用构造函数实例化
当执行 super() 方法时,父类 Parent 的构造函数会执行并初始化父类的实例属性,然后才会继续执行子类 Child 的构造函数。在子类的构造函数中,才会对子类的实例属性比如child.num进行初始化
问题内容: 我有一个抽象基类,用作我的单元测试(TestNG 5.10)的基础。在该类中,我将初始化测试的整个环境,设置数据库映射等。此抽象类具有一个带有注释的方法,该方法可以进行初始化。 接下来,我用具有方法和方法的特定类扩展该类。这些方法对环境进行类特定的初始化(例如,将一些记录放入数据库中)。 如何执行带注释的方法的特定顺序?我需要先执行抽象基类中的那些,然后再执行扩展类中的那些。 例: 预
为了说明这一点,我们创建一个动物园应用,其中创建鸟类。在经典继承中,我们定义一个基类,然后将其子类化以创建一个派生类。 类定义了Penguin类继承的方法walk,并且可以被Penguin对象的实例使用。 同样,Penguin类定义了不能用于Bird对象的方法swim。 继承从上到下从基类到它的子类。 对象初始化 对象创建的顺序从它的基类开始,然后向下移动到任何子类。 // JavaScript
我在Java实践继承,面临以下问题: 父类的代码: 子类代码: 两者是分开的。java文件。当我尝试执行父类文件时,它可以工作,但由于某些原因,我甚至无法运行子类。这里有以下信息: 该文件于2月8日发布。java不是可执行的。请选择要运行的主类 我该如何解决这个问题?
题目描述 如下图所示,利用chrome的devtools工具查看当前执行代码处的的Local Scope,发现此时this为undefined,但是为何this.visible在实际执行过程中没有报错? 题目来源及自己的思路 问题来源于vue文件中的一段函数代码,我的问题及思路如下 我知道箭头函数的this指向来源于所在上下文,此时应该是指向Vue实例 但是为何在devtool中Debug过程,此
打印2的位置 怎么解释呢
问题内容: 考虑下面的代码 基于我对类成员初始化和构造函数执行顺序的理解。我期望输出是 因为我相信类成员甚至在调用main方法之前就已初始化。但是当我运行程序时,我得到以下输出 我的困惑是,尽管Meal()Lunch()和PortableLunch()在Bread()Cheese()和Lettuce()之前运行,即使它们的构造函数被调用。 问题答案: 这些是实例字段 它们仅在创建实例时存在(执行)