7

May be I'm missing something here. Please bear with me as I'm new to OOP in javascript. But I need to find a solution to my problem.

I have this code.

var parent = function() {}
parent.prototype.someFunc = function() {
  return "a string";
}

Now I'm trying to inherit the parent using the code like below,

var child = function() {
    parent.call(this);
}
child.prototype = new parent();

When I do like this it works.

var obj = new child();
obj.someFunc();

But I would like to have someFunc() inside child like below,

var child = function() {
  parent.call(this);
  var someVal = this.someFunc(); // method from parent.
}
child.prototype = new parent();

Doing that will throw me an error as Uncaught TypeError: Object [object global] has no method 'getLightBox' But as I know this refers to the current object and I'm just confused here about how to solve this problem. Please correct me if I'm wrong. Or if there is a better way then I would like to know about it.

Erik Schierboom
  • 16,301
  • 10
  • 64
  • 81
Vinay
  • 6,891
  • 4
  • 32
  • 50
  • It works fine in firefox – simonzack Jun 08 '13 at 07:40
  • working .. http://jsfiddle.net/TH3h2/ – Diode Jun 08 '13 at 07:42
  • Yup, working fine, always good to test it and provide live example: http://jsbin.com/oyineb/1/edit – elclanrs Jun 08 '13 at 07:43
  • @elclanrs your example solved my problem. Thanks – Vinay Jun 08 '13 at 08:00
  • You should not use `var someVal` this will only be available in the body of the child function and can't be accessed by prototype functions (child.prototype.whatever=function(){//no someVal here). `Use this.someVal` instead. – HMR Jun 08 '13 at 08:08
  • 3
    FWIW, don't do `child.prototype = new parent();`. You don't want to create a new instance at this point. Use `child.prototype = Object.create(parent.prototype);` instead. The error seems to indicate that you are missing `new` somewhere. – Felix Kling Jun 08 '13 at 08:09
  • @FelixKling that was a perfect one. Solved some problems as well. Thanks a lot. – Vinay Jun 08 '13 at 08:19
  • Here is a great post on the subject http://alexsexton.com/blog/2013/04/understanding-javascript-inheritance/ – Andrei Rosca Jun 08 '13 at 08:21
  • @FelixKling You missed defining the `constructor` property, and the ES 5 method `Object.create()` must be feature-tested or emulated before in any case. See also [my answer to "What is the reason to use the 'new' keyword here?"](http://stackoverflow.com/a/12593269/855543). – PointedEars Jun 08 '13 at 08:52
  • @PointedEars: That's why it was a comment and not an answer. I also think that assigning the correct `constructor` property is good, but technically it is not necessary. The [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) provides a polyfill for `Object.create`. – Felix Kling Jun 08 '13 at 15:08
  • @FelixKling It is technically necessary because it makes sure that comparisons against the `constructor` property will still work. The current "polyfill" at MDN is *wrong* as the built-in `Object.create()` accepts *two* arguments (and more, but they are ignored). – PointedEars Jun 08 '13 at 16:22

5 Answers5

3

You are forgetting to use new. I.E. you have code that does child(...) instead of new child(...)

Some tips:

Also

  • Don't use new for linking prototype, just do Child.prototype = Object.create(Parent.prototype)
Esailija
  • 138,174
  • 23
  • 272
  • 326
2

The preferred solution

Javascript OOP is specific in context handling: if your parent works with context (this), just call the parent in the child with its context (note the new function(), which sets the context from global to the newly created object):

var parent = function() { // constructor, should be called with new
  this.someFunc = function() { return "a string"; }
}

var child = new function() { // object, was already called with new
  parent.call(this); // set parent context to child's, don't create new one
  var someVal = this.someFunc(); // method from parent.
}

console.log(child.someFunc()); // a string

Alternative, non-standard solution, close to your approach

If you set the parent prototype instead of working with its context, you may use non-standard __proto__ member, which has access to its prototype:

var parent = function() {} // constructor to create empty object
parent.prototype.someFunc = function() { // someFunc is in parent prototype
  return "a string";
}

var child = new function() {
  this.__proto__ = new parent(); // set prototype to parent with its own context
  var someVal = this.someFunc(); // method from parent.
}

console.log(child.someFunc()); // a string

Compared to your working example

You may also set the prototype to the constructor, not to the object using standard prototype. Note the object is created AFTER the prototype is set, see the position of new calls and compare it to the Felix Kling's comment to the question:

var parent = function() {}
parent.prototype.someFunc = function() {
  return "a string";
}

var child = function() { // no new here
  var someVal = this.someFunc();
}
child.prototype = new parent();

console.log((new child).someFunc()); // new moved here

The error explained

Function with new creates a constructor from function in javascript. It means that the context becomes the function itself. Without the new (and with default non-strict behavior), the context is global context, hence your error

Object [object global] has no method 'someFunc'
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
2

Hey buddy here you are wrong with your concepts. First u need to know about the following issues that u did in the code

You have used combined form of Inheritence here.
Prototype Chaining(Implementation Inheritence) in the way that child's prototype is instance of parent //somefunc() is actually getting inherited this way into child's prototype not the child's instance//

Constructor Stealing(Classical Inheritence) by calling Parent constructor from with in Child Constructor //Nothing getting inherited this way//

So the issue here is u have encountered a problem that almost every beginner does with Combined Inheritence. The problem is

In combined Inheritence we call SuperType(parent) twice. Once by classical Inheritence and other by making child.prototype an instance of parent You made the first call from classical inheritence(ie. from within the child constructor) .Till this time u haven't created child.prototype as an instance of parent object and u are using this.someFunc() that is assigned to the instance of child via prototype inheritence.This is the cause of error.

Solution: Make the first call to parent object for setting child prototype as an instance of parent object[child.prototype=new parent();] ans then make the second call [creating instance of child]..

In short I meant this

<script>
var parent = function() {}
parent.prototype.someFunc = function() {
  return "a string";
}
var child = function() {
  parent.call(this);
  someVal = this.someFunc(); // method from parent.
}
child.prototype = new parent();
var obj = new child();

alert(someVal);
</script>

Better solution would be using Parasitic Combination Inheritence in which parent object is called only once by classical inheritence.

chetan mehta
  • 369
  • 1
  • 3
  • 13
1

make sure that the function you are trying to call is on the prototype of the parent object , not on the object it self ( class method vs "static" method ) if the method is "static" you cant call it in the child class with this but with

parent.method.call(this)
mpm
  • 20,148
  • 7
  • 50
  • 55
1

I'm not sure what you're expecting but if you'd like someVal to be a property of Child and be accessed after the instance is created then you should declare it with this.someVal instead of var someVal.

Variables declared in a function body that is meant to create object instances with var is a bad idea beacause these are only available in the function body and not in prototype functions.

A basic explanation of how JS prototype works can be found here: Prototypical inheritance - writing up

The code you provided should work without a problem:

var parent = function() {}
parent.prototype.someFunc = function() {
  return "a string";
}
var child = function() {
  parent.call(this);
  var someVal = this.someFunc(); // method from parent.
  console.log("someval in child body",someVal);
  this.publicProp=this.someFunc();
}
child.prototype = new parent();

var c = new child();
console.log("return value of someFunc",c.publicProp);
Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • No its not about variables of child but parent prototypes methods. I understand what you said but not the one which I'm looking for. – Vinay Jun 08 '13 at 08:09
  • @JJPA As you can see in my updated answer, you code should run without a problem. Parent.prototype stuff becomes Child.prototype stuff afer the line `Child.prototype=new parent()` if you were to create variable `c = new child()` before setting child.prototype to new parent you would get an exception. – HMR Jun 08 '13 at 08:13