简体   繁体   English

JavaScript从子对象调用父函数

[英]JavaScript call parent function from child object

I am new to Object Oriented Programming with javascript. 我是javascript的面向对象编程的新手。 And trying to implement the basics that we know from other programming languages. 并尝试实现我们从其他编程语言中了解的基础知识。

I have two classes, one parent and one child. 我有两个班,一个家长和一个孩子。 Parent have some private functions and some public functions. 父母有一些私人功能和一些公共功能。 Child will inherit parent class. Child将继承父类。

And I wish to access parent public function from child object. 我希望从子对象访问父公共函数。 What I am trying to do: 我想做什么:

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

I am getting this error when running this: 我在运行时收到此错误:

Uncaught TypeError: undefined is not a function 未捕获的TypeError:undefined不是函数

Am I doing something which is incorrect.? 我做的是不正确的事吗? Thanks in advance! 提前致谢!

JavaScript OOP does not work like Java's or C#, don't expect it to, and do not try to make it. JavaScript OOP不像Java或C#那样工作,不要指望它,也不要尝试制作它。 The only thing that will result from so doing is misunderstandings. 这样做的唯一原因是误解。 Instead of trying to force your old paradigms on a language that is built up entirely different, rather learn how JavaScript OOP works. 而不是试图强制你的旧范式完全不同的语言,而是学习JavaScript OOP的工作原理。

JavaScript is Object Oriented, but that doesn't mean it has classes. JavaScript是面向对象的,但这并不意味着它有类。 At least not in the way most developers coming from Java or similar languages think of classes. 至少不是大多数来自Java或类似语言的开发人员都会想到类。 It does not have classical inheritance either. 它也没有经典继承。 However, all of these can be "faked", or mimicked (which is what you're effectively trying to do). 但是,所有这些都可以“伪造”或模仿(这是你有效地尝试做的)。 The problem with so doing, is the fact that developers coming from Java or similar see code that looks like classes and classical inheritance, so they think it's classes with classical inheritance, and expect it to behave as such, whereas it might end up working completely different. 这样做的问题是,来自Java或类似的开发人员看到类似于类和经典继承的代码,因此他们认为它是具有经典继承的类,并期望它表现得如此,而它可能最终完全工作不同。

Let's start with your SuperClass function (because that's what it is. It's a function, not a class). 让我们从你的SuperClass函数开始(因为它就是它。它是一个函数,而不是一个类)。 First of all, your code isn't even valid syntax, because your SuperClass function does not parenthesizes. 首先,您的代码甚至不是有效的语法,因为您的SuperClass函数没有括号。 The correct syntax would be function SuperClass() { ... } . 正确的语法是function SuperClass() { ... }

Secondly, JavaScript uses prototypes to handle inheritance between objects (not classes), and if you want to do prototypical inheritance (which some of your code suggest you want to), you can't return a new, anonymous object from the SuperClass function. 其次,JavaScript使用原型来处理对象(而不是类)之间的继承,如果你想做原型继承(你的一些代码建议你想要),你就不能从SuperClass函数返回一个新的匿名对象。 Allow me to illustrate a bit what goes on here. 请允许我说明一下这里发生了什么。

When you call your SuperClass function (either from the childClass function, or from any other place) using the new keyword, as in var inst = new SuperClass(); 使用new关键字调用SuperClass函数(来自childClass函数或来自任何其他地方)时,如var inst = new SuperClass(); , what effectively happens is the following: ,有效发生的是以下几点:

  1. JavaScript creates a new blank object, which prototype is equal to the prototype -property on the function you're calling. JavaScript创建一个新的空白对象,该原型等于您正在调用的函数的prototype -property。 In code this would be var temp = Object.create(SuperClass.prototype); 在代码中,这将是var temp = Object.create(SuperClass.prototype); .
  2. JavaScript calls your function with that object as the this object. JavaScript使用该对象调用您的函数作为this对象。 In code this would be SuperClass.call(temp, <arguments>) . 在代码中,这将是SuperClass.call(temp, <arguments>)
  3. If the function returns anything, inst is set to that value, else, it's set to the temp value. 如果函数返回任何内容,则将inst设置为该值,否则将其设置为temp值。

Now, in your SuperClass function you do the following: 现在,在您的SuperClass函数中,您执行以下操作:

//Constructor implementation of this class

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

What happens here is that your SuperClass method get's invoked with a this , which is an instance of SuperClass , ie. 这里发生的是,你的SuperClass方法得到的以调用this ,这是一个实例SuperClass ,即。 it has SuperClass.prototype in it's prototype chain. 它的原型链中有SuperClass.prototype This would mean that if you for instance did this instanceof SuperClass , you would get true , as you would expect. 这意味着,如果您this instanceof SuperClass ,那么您将会如您所料那样成为true Then you go and return a new, anonymous object, which has a property named parentPublicFunction (which just happens to be a function, but could be anything). 然后你去返回一个新的匿名对象,它有一个名为parentPublicFunction的属性(恰好是一个函数,但可以是任何东西)。 This new object you return, is not an instance of SuperClass . 您返回的这个新对象不是SuperClass的实例。 It does not have SuperClass.prototype in it's property. 它的属性中没有SuperClass.prototype You've created a situation where if I do (new SuperClass()) instanceof SuperClass you get false. 您已经创建了一种情况,如果我这样做(new SuperClass()) instanceof SuperClass您就会得到错误。 In other word, the instance you return from your SuperClass constructor function, does not implement your "class". 换句话说,从SuperClass构造函数返回的实例不会实现您的“类”。 This is probably not at all what you intended, which is one of the reasons you cannot just strap classical inheritance principles on JavaScript and expect things to function the same. 这可能完全不是你想要的,这也是你不能仅仅在JavaScript上使用经典继承原则并期望事物运行相同的原因之一。

Now, what we have so far, is a function name SuperClass , which returns an Object without any relation to SuperClass . 现在,我们到目前为止,是一个函数名称SuperClass ,它返回一个与SuperClass没有任何关系的Object SuperClass has a prototype which is empty, meaning that even if you did somehow manage to create objects with SuperClass.prototype in it's prototype chain, it would not inherit anything from SuperClass , because there is nothing defined to inherit. SuperClass有一个空的原型,这意味着即使你以某种方式设法在其原型链中创建具有SuperClass.prototype对象,它也不会从SuperClass继承任何东西,因为没有任何定义可以继承。 Which brings us to the childClass function. 这将我们带到了childClass函数。

First off all, I'll be naming it ChildClass instead of childClass . 首先,我将命名为ChildClass而不是childClass Any function in JavaScript you expect people to call with new should start with an upper case. 您期望人们使用new调用的JavaScript中的任何函数都应以大写字母开头。 Any function you don't expect to be called with new should be started with a lower case. 您不希望使用new调用的任何函数都应以小写字母开头。 There is no way in JavaScript to know if a function is intended to be called with or without new , so this is used to signify. 在JavaScript中无法知道函数是否打算使用或不使用new来调用,因此这用于表示。

Now, ChildClass.prototype is set up as a instance of SuperClass , meaning that any methods in SuperClass 's prototype will be callable from an instance of ChildClass . 现在, ChildClass.prototype被设置为SuperClass一个实例,这意味着SuperClass原型中的任何方法都可以从ChildClass的实例中调用。 And any instance of ChildClass is also an instance of SuperClass (just as you'd expect). ChildClass任何实例也是SuperClass一个实例(就像你期望的那样)。 However, as already explained, the prototype of SuperClass is empty, so there is nothing to inherit from it. 但是,正如已经解释过的那样, SuperClass的原型是空的,所以没有什么可以继承它。 Therefore, the only thing ChildClass gains from this inheritance is the fact that a instanceof ChildClass implies that a instanceof SuperClass . 因此, ChildClass从此继承中获得的唯一事实是a instanceof ChildClass意味着a instanceof SuperClass However, just as with SuperClass , you return a anonymous object from ChildClass , which again result in the fact that (new ChildClass()) instanceof ChildClass is false. 但是,就像在SuperClass ,您从ChildClass返回一个匿名对象,这又导致(new ChildClass()) instanceof ChildClass为false。

And therein, lies (most) of your problems. 其中,存在(大多数)你的问题。 The solution is simply to learn how OOP works in JavaScript and embrace that when doing JavaScript, instead of trying to bend it to how you assume things to work. 解决方案只是为了了解OOP如何在JavaScript中运行并在执行JavaScript时接受它,而不是试图将其弯曲到您认为工作的方式。

Because you are returning your own objects from the constructor functions, you have to do a little more plumbing. 因为要从构造函数返回自己的对象,所以必须多做一些管道。

//Call to super constructor
this.parent.constructor.call(this, arguments);

returns the public API of SuperClass but you are not doing anything with the result. 返回SuperClass的公共API,但是你没有对结果做任何事情。 You'd have to merge it into the child's public 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
    }
});

Assigning to childClass.prototype is actually irrelevant in your case, because the object you return from the constructors doesn't inherit from it anyway. 在您的情况下,分配给childClass.prototype实际上是无关紧要的,因为从构造函数返回的对象无论如何都不会从它继承。 Ie childObj won't have any of the properties you assigned to the prototype (such as parent ). childObj将不具有您分配给原型的任何属性(例如parent )。 There are even more things you miss out by returning your own object, such as being able to use instanceOf ( childObj instanceOf childClass will be false ). 通过返回自己的对象,你会错过更多的东西,例如能够使用instanceOfchildObj instanceOf childClass将为false )。

To make that all of that work you have to assign the methods to this inside the constructor (instead of returning an object). 为了让所有的工作,你必须在方法分配给this构造函数中(而不是返回的对象)。 You can find more information about that style of OOP in the MDN documentation . 您可以在MDN文档中找到有关该OOP样式的更多信息。


Note: It is convention to start the names of constructor functions with a capital letter, ie ChildClass . 注意:通常使用大写字母(即ChildClass来启动构造函数的名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM