我是使用javascript进行面向对象编程的新手。并尝试实现我们从其他编程语言中了解的基础知识。
我有两个班,一个是父母,一个是孩子。父母有一些私人功能和一些公共功能。 Child将继承父类。
我希望从子对象访问父公共函数。我想做什么:
function SuperClass {
//Constructor implementation of this class
//public functions
return {
parentPublicFunction: function() {
//Public function implementation
}
}
function privateFunction() {
//Private function implementation.
}
}
//Inheriting
childClass.prototype = Object.create(SuperClass.prototype);
childClass.prototype.constructor = childClass;
childClass.prototype.parent = SuperClass.prototype;
function childClass {
//Call to super constructor
this.parent.constructor.call(this, arguments);
//Public function for childClass.
return {
childPublicFunction: function() {
//function implementation
}
}
}
var childObj = new childClass();
childObj.parentPublicFunction();
我在运行时收到此错误:
未捕获的TypeError:undefined不是函数
我做的事情是不正确的。?提前谢谢!
答案 0 :(得分:7)
JavaScript OOP不像Java或C#那样工作,不要期望它,也不要尝试制作它。这样做的唯一原因是误解。而不是试图强制你的旧范式完全不同的语言,而是学习JavaScript OOP的工作原理。
JavaScript是面向对象的,但这并不意味着它有类。至少不是大多数来自Java或类似语言的开发人员都会想到类。它也没有经典继承。但是,所有这些都可以伪造成模仿(这是你有效地尝试做的事情)。这样做的问题是,来自Java或类似的开发人员看到类似于类和经典继承的代码,因此他们认为它具有经典继承的类,并期望它表现得如此,而它可能最终工作完全不同。
让我们从你的SuperClass
函数开始(因为它是什么。它是一个函数,而不是一个类)。首先,您的代码甚至不是有效的语法,因为您的SuperClass
函数没有括号。正确的语法是function SuperClass() { ... }
。
其次,JavaScript使用原型来处理对象(而不是类)之间的继承,如果你想做原型继承(你的一些代码建议你想要),你就不能返回一个新的匿名对象来自SuperClass
函数。请允许我举例说明这里发生的事情。
当您使用SuperClass
关键字时,使用childClass
关键字来呼叫new
功能时,或var inst = new SuperClass();
关键字如下:
prototype
- 属性。在代码中,这将是var temp = Object.create(SuperClass.prototype);
。this
对象调用您的函数。在代码中,这将是SuperClass.call(temp, <arguments>)
。inst
将设置为该值,否则,它将设置为temp
值。现在,在您的SuperClass
功能中,您可以执行以下操作:
//Constructor implementation of this class
//public functions
return {
parentPublicFunction: function() {
//Public function implementation
}
}
function privateFunction() {
//Private function implementation.
}
这里发生的事情是,您使用SuperClass
调用了this
方法,SuperClass
是SuperClass.prototype
的实例,即。它有this instanceof SuperClass
个原型链。这意味着如果您例如true
,那么您会得到parentPublicFunction
,正如您所期望的那样。然后你去返回一个新的匿名对象,它有一个名为SuperClass
的属性(恰好是一个函数,但可以是任何东西)。您返回的这个新对象不是SuperClass.prototype
的实例。它的属性中没有(new SuperClass()) instanceof SuperClass
。你已经创造了一种情况,如果我SuperClass
你就会弄错。换句话说,您从SuperClass
构造函数返回的实例未实现您的&#34;类&#34;。这可能完全不是你想要的,这也是你不能仅仅在JavaScript上绑定经典继承原则并期望事物运行相同的原因之一。
现在,我们目前所拥有的是一个函数名Object
,它返回一个与SuperClass
没有任何关系的SuperClass
。 SuperClass.prototype
有一个空的原型,这意味着即使你以某种方式设法在其原型链中创建SuperClass
的对象,它也不会继承childClass
中的任何内容,因为没有任何定义可以继承。这将我们带到ChildClass
函数。
首先,我将命名为childClass
而不是new
。您期望人们使用new
调用的JavaScript中的任何函数都应以大写字母开头。您希望通过new
调用的任何功能都应以小写字母开头。在JavaScript中无法知道函数是否打算使用或不使用ChildClass.prototype
进行调用,因此这用于表示。
现在,SuperClass
已设置为SuperClass
的实例,这意味着ChildClass
原型中的所有方法都可以从{{1}的实例调用}。 ChildClass
的任何实例也是SuperClass
的实例(正如您所期望的那样)。但是,正如已经解释过的那样,SuperClass
的原型是空的,所以没有什么可以继承它。因此,ChildClass
从a instanceof ChildClass
获得a instanceof SuperClass
意味着SuperClass
这一事实唯一可以获得ChildClass
。但是,与(new ChildClass()) instanceof ChildClass
一样,您从{{1}}返回一个匿名对象,这又导致{{1}}为假。
其中,存在(大多数)你的问题。解决方案只是为了了解OOP如何在JavaScript中运行并在执行JavaScript时接受它,而不是试图将其弯曲到您认为工作的方式。
答案 1 :(得分:5)
因为你从构造函数返回自己的对象,所以你必须做更多的管道。
//Call to super constructor
this.parent.constructor.call(this, arguments);
返回SuperClass
的公共API,但您没有对结果做任何事情。您必须将其合并到孩子的公共API中:
//Call to super constructor
var parentAPI = this.parent.constructor.call(this, arguments);
//Public function for childClass.
return Object.assign(parentAPI, {
childPublicFunction: function() {
//function implementation
}
});
分配给childClass.prototype
实际上与您的情况无关,因为从构造函数返回的对象无论如何都不会从它继承。即childObj
没有您分配给原型的任何属性(例如parent
)。通过返回自己的对象,您可能会错过更多的内容,例如能够使用instanceOf
(childObj instanceOf childClass
将false
)。
为了完成所有这些工作,您必须将方法分配给构造函数内的this
(而不是返回对象)。您可以在MDN documentation中找到有关该OOP样式的更多信息。
注意:通常用大写字母开始构造函数的名称,即ChildClass
。