JavaScript 从子对象调用父函数

JavaScript call parent function from child object

本文关键字:函数 调用 对象 JavaScript      更新时间:2023-09-26

我是javascript面向对象编程的新手。并尝试实现我们从其他编程语言中知道的基础知识。

我有两个班级,一个家长和一个孩子。父母有一些私人功能和一些公共功能。子类将继承父类。

我希望从子对象访问父公共函数。我想做什么:

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();

运行此程序时出现此错误:

捕获的类型错误:未定义不是函数

我是否在做不正确的事情。?提前感谢!

JavaScript OOP不像Java或C#那样工作,不要指望它,也不要试图做到这一点。这样做唯一会导致误解。与其试图将你的旧范式强加于一种完全不同的语言,不如学习JavaScript OOP是如何工作的。

JavaScript是面向对象的,但这并不意味着它有类。至少不是大多数来自Java或类似语言的开发人员对类的看法。它也没有经典继承。但是,所有这些都可以"伪造"或模仿(这是您实际上试图做的事情)。这样做的问题在于,来自Java或类似语言的开发人员看到的代码看起来像类和经典继承,所以他们认为它是具有经典继承的类,并期望它表现得如此,而它最终可能会完全不同。

让我们从您的SuperClass函数开始(因为它就是这样。它是一个函数,而不是一个类)。首先,你的代码甚至不是有效的语法,因为你的SuperClass函数没有括号。正确的语法是 function SuperClass() { ... } .

其次,JavaScript 使用原型来处理对象(而不是类)之间的继承,如果你想做原型继承(你的一些代码建议你想要这样做),你不能从 SuperClass 函数返回一个新的匿名对象。请允许我稍微说明一下这里的情况。

当您使用 new 关键字调用 SuperClass 函数(从 childClass 函数或任何其他位置)时,如 var inst = new SuperClass(); 中所示,实际发生的情况如下:

  1. JavaScript 创建一个新的空白对象,该原型等于您正在调用的函数上的 prototype -属性。在代码中,这将var temp = Object.create(SuperClass.prototype);.
  2. JavaScript 使用该对象作为this对象调用您的函数。在代码中,这将SuperClass.call(temp, <arguments>).
  3. 如果函数返回任何内容,则inst设置为该值,否则,它将设置为temp值。

现在,在SuperClass函数中执行以下操作:

//Constructor implementation of this class
//public functions
return {
    parentPublicFunction: function() {
        //Public function implementation
    }
}
function privateFunction() {
    //Private function implementation.
}

这里发生的事情是,你的SuperClass方法get被调用this,这是SuperClass的一个实例,即它在原型链中具有SuperClass.prototype。这意味着,例如,如果你做this instanceof SuperClass,你会得到true,正如你所期望的那样。然后你返回一个新的匿名对象,它有一个名为 parentPublicFunction 的属性(它恰好是一个函数,但可以是任何东西)。您返回的这个新对象不是 SuperClass 的实例。它的财产中没有SuperClass.prototype。你创造了一种情况,如果我这样做(new SuperClass()) instanceof SuperClass你就会得到错误。换句话说,您从SuperClass构造函数返回的实例不会实现您的"类"。这可能根本不是你的意图,这就是为什么你不能只在 JavaScript 上绑定经典继承原则并期望事情运行相同的原因之一。

现在,到目前为止,我们得到的是一个函数名称 SuperClass ,它返回一个与SuperClass没有任何关系的ObjectSuperClass有一个空的原型,这意味着即使您以某种方式设法在其原型链中创建了带有SuperClass.prototype的对象,它也不会从SuperClass继承任何东西,因为没有定义要继承的内容。这就把我们带到了childClass函数。

首先,我将它命名为ChildClass而不是childClass。JavaScript 中您希望人们使用 new 调用的任何函数都应该以大写字母开头。任何不希望用new调用的函数都应该以小写字母开头。在JavaScript中没有办法知道一个函数是打算在有new的情况下还是没有的情况下调用,所以这是用来表示的。

现在,ChildClass.prototype被设置为SuperClass的实例,这意味着SuperClass原型中的任何方法都可以从ChildClass的实例中调用。任何ChildClass实例也是SuperClass的实例(正如您所期望的那样)。但是,如前所述,SuperClass的原型是空的,因此没有什么可以从中继承的。因此,ChildClass从这种继承中获得的唯一好处是a instanceof ChildClass暗示a instanceof SuperClass .然而,就像SuperClass一样,你从ChildClass返回一个匿名对象,这再次导致(new ChildClass()) instanceof ChildClass是假的事实。

其中,是你的(大部分)问题。解决方案只是学习OOP在JavaScript中是如何工作的,并在做JavaScript时接受它,而不是试图把它弯曲到你假设事情是如何工作的。

因为您要从构造函数返回自己的对象,所以您必须做更多的管道。

//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 )。返回自己的对象会错过更多的东西,例如能够使用instanceOfchildObj instanceOf childClass将被false)。

使所有这些工作完成,您必须在构造函数中分配要this的方法(而不是返回对象)。您可以在 MDN 文档中找到有关该 OOP 样式的更多信息。


注意:构造函数的名称通常以大写字母开头,即 ChildClass .