【问题标题】:How to properly subclass a subclass in JavaScript?如何在 JavaScript 中正确子类化子类?
【发布时间】:2016-12-31 05:26:05
【问题描述】:

我以为我对如何在 JavaScript 中正确扩展类有很好的理解,但是在扩展子类时,当我覆盖一个方法并从子类调用父方法时,我遇到了一个无限循环。我要么做错了,要么你不应该在 JavaScript 中这样子类化。

有人可以帮我介绍一下吗?

var Grand = function() {
	this.test();
};

Grand.prototype.constructor = Grand;

Grand.prototype.test = function() { 
	console.log( "Grand!")
};



var Parent = function() {
  this.supr.constructor.call( this );
};

Parent.prototype = Object.create( Grand.prototype );
Parent.prototype.constructor = Parent;
Parent.prototype.supr = Grand.prototype;

Parent.prototype.test = function() { 
	this.supr.test.call( this );
  console.log( "Parent!" );
};



var Child = function() {
  this.supr.constructor.call( this );
};

Child.prototype = Object.create( Parent.prototype );
Child.prototype.constructor = Child;
Child.prototype.supr = Parent.prototype;

Child.prototype.test = function() { 
	this.supr.test.call( this );
  console.log( "Child!" );
};



var g = new Grand(); // Outputs "Grand!"
var p = new Parent(); // Outputs "Grand!" "Parent!"
var c = new Child(); // Error: Endless Loop!

我希望控制台记录“Grand!”、“Parent!”、“Child!”当实例化一个新的 Child() 时,我得到了一个无限循环。

我来自 ActionScript 背景,因此在 JavaScript 中创建类仍然会让我感到很困惑。提前感谢您的帮助!

【问题讨论】:

  • 在 JavaScript 中并没有真正的类和子类的概念(除了 ES6 中的糖语法)。 JavaScript 是原型基础。

标签: javascript class inheritance


【解决方案1】:

问题在于这段代码:

var Parent = function() {
  this.supr.constructor.call( this );  
};

考虑一下这段代码执行时会发生什么:

var c = new Child();

这里this 是变量c,因此this.supr.constructor 将始终是父级的构造函数,就像这些代码行中的设置一样:

Child.prototype.supr = Parent.prototype;  // i.e. this.supr = Parent.prototype
Parent.prototype.constructor = Parent;  // i.e. this.supr.constructor = Parent

因此,当 Child 的构造函数调用 this.supr.constructor.call( this ); 时,它会执行 Parent 函数,而父函数再次执行 this.supr.constructor.call( this ); 导致再次调用 Parent 函数,从而导致无限循环。

解决方法是调用基类函数,如下所示:

var Child = function() {
  Child.prototype.supr.constructor.call( this );
};

更多详情this post

【讨论】:

  • 我需要弄清楚这一点,但这确实有些道理。谢谢!
【解决方案2】:

我建议切换到 es6。这种原型设计可能是一团糟,而且更难跟踪。但是,如果您在浏览器中需要它,您应该将您的代码转换为 es5 whit babel 等。在 Node 环境中,只要您有最新版本,它就可以了。一些最新的浏览器也支持它

class Grand {
    constructor() {
        this.test()
    }

    test() {
        console.log( "Grand!")
    }
}

class Parent extends Grand {
    test() {
        super.test()
        console.log( "Parent!" )
    }
}

class Child extends Parent {
    test() {
        super.test()
        console.log( "Child!" )
    }
}

let g = new Grand(); // Outputs "Grand!"
let p = new Parent(); // Outputs "Grand!" "Parent!"
let c = new Child(); // Outputs "Grand!" "Parent! "child!"

不仅可读性更高,而且代码更少,更易理解

【讨论】:

  • 老实说,我宁愿使用 ES6,也不愿学习 TypeScript 或 Dart。我对 Babel 不太熟悉,它是否经过实战考验并且足够强大,我可以依赖它来完成客户项目?谢谢!
  • Babel 非常坚固。并且请不要使用其他可以转换为 javascript 的语言(如 Dart 或 coffescript)进行编码。 coffescript是互联网上最爱恨的东西
  • 如果代码不能在任何浏览器/节点环境中执行,那么不要使用它,因为它最终将支持任何一些组成的语言试图实现的任何东西。他们还需要跟上最新的 javascript 版本,否则他们将落后并消失。
猜你喜欢
  • 1970-01-01
  • 2013-06-13
  • 2016-04-19
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2015-02-18
  • 2020-06-03
  • 1970-01-01
相关资源
最近更新 更多