3

I'm trying to better understand inheritance in javascript. My goal is to write a function that declares some variables and sets up an environment so that other functions can build off of it. I'm kind of thinking along the lines of mixins in Ruby. Here is a simple example that is not working.

function baseFunction(){

  this.my_var = "hello world";

};

function speakMessage(){

  alert(this.my_var);

}

speakMessage.prototype = baseFunction();

speakmessage();

I thought if I set the prototype the baseFunction than any properties not found in the speakMessage function will be searched for in the baseFunction. Is that not right? How cna I get this to work?

5
  • 1
    Do you know what closures are? Commented Jan 3, 2014 at 19:01
  • This code doesn't do what you think it does. When you call baseFunction(), this will actually be window! You need to use the new keyword. speakMessage.prototype = new baseFunction();, and then new speakMessage(); Commented Jan 3, 2014 at 19:10
  • This is an interesting subject, the combination of prototype. i am use to just using new .... anyone have a clue where i can read about it farther ? Commented Jan 3, 2014 at 19:13
  • The following answer may help you understand how to create instances using a constructor function and how one constructor function can inherit from another through prototype and invoking Parent.apply(this,arguments); stackoverflow.com/a/16063711/1641941 Commented Jan 4, 2014 at 4:14
  • @NetaMeta You are correct, you should use new if you'd like to speakMessage to inherrit from baseFunction. Currently setting speakMessage.prototype to the result of baseFunction (=undefined) wil set window.my_var (because calling baseFunction with window as the invoking object) and later alert "Hello World" because speakMessage is called with window as the invoking object. Got nothing to do with speakMessage inheriting anything from baseFunction. Commented Jan 4, 2014 at 4:24

3 Answers 3

4

Trivial answer, but... speakMessage(); (big M) :-)

Javascript is case-sensitive.

And great comment from HMR I missed: functions act like constructors if used with new in Javascript. Note the two new I added to your code:

my_var = "goodbye world";

function baseFunction() {
  this.my_var = "hello world";
}

function speakMessage() {
  alert(this.my_var);
}

speakMessage.prototype = new baseFunction(); // new: inherit from object
new speakMessage(); // object constructor: hello world
speakMessage(); // function: goodbye world from window object context

Also have a look at HMR's answer.

Sign up to request clarification or add additional context in comments.

4 Comments

@asolberg exactly :-) making my answer less brief, you could look at bind() which enables you to play with this. Also have a look at apply() and call functions.
The only reason that works is because this is window and setting speakMessage.prototype to undefined (because baseFunction doesn't return anything) does not make speakMessage inherit anyting. All it does is set window.my_var and later alert it because speakMessage is called with window as the invoking object. Got nothing to do with speakMessage inheriting anything from baseFunction.
@HMR: I missed it, great comment! I updated my answer to clarify how the context works and upvoted your answer for clarifying it even more.
@HMR - Thanks. I understand it much more clearly now. At first I was approaching from the wrong angle of "mixing" in functions ala Ruby style but I see now Javascript is prototypal and only through setting prototypes can you shape the prototype chain which will then determine your inheritance hierarchy.
2

Tiny error. You called speakmessage(); when you created the function speakMessage(){}

This should fix it.

function baseFunction(){

  this.my_var = "hello world";

};

function speakMessage(){

  alert(this.my_var);

}

speakMessage.prototype = baseFunction();

speakMessage();

1 Comment

The fact that it gives the expected output does not make it work. Question suggest OP would like to inherit. My guess speakMessage should inherit from baseFunction.
2

For future stumblers upon; the answers given before only address a typo in the OP's question. As for speakMessage inheriting from baseFunction the OP's code is completely wrong and should/could look something like this:

(note that constructor functions should start with a capital letter)

function BaseFunction(args){
  //name is instance specific
  //defaults to World
  this.name = (args&&args.name)?args.name:"World";
};
//shared members 
BaseFunction.prototype.saySomething=function(){
  return "From BaseFunction:"+this.name;
};

function SpeakMessage(args){
  //re use BaseFunction constructor code
  BaseFunction.call(this,args);
}
//inherit shared members from prototype
SpeakMessage.prototype = Object.create(BaseFunction.prototype);
//repair built in constructor value (or it'll point to BaseFunction)
SpeakMessage.prototype.constructor=SpeakMessage;
//extend saySomething, this is optional an shows how
// to add extra functionality to existing Parent functions
SpeakMessage.prototype.saySomething=function(){
  return BaseFunction.prototype.saySomething.call(this) + 
    ", from SpeakMessage:"+this.name;
};

var world = new SpeakMessage();//defaults name to be "world"
//following will output: From BaseFunction:World, from SpeakMessage:World
console.log(world.saySomething());
var op = new SpeakMessage({name:"OP"});
//following will output:From BaseFunction:OP, from SpeakMessage:OP
console.log(op.saySomething());
var parent = new BaseFunction();
console.log(parent.saySomething());//=From BaseFunction:World

As in comments; for more info about constructor functions and prototype: https://stackoverflow.com/a/16063711/1641941

As for the comment mentioning closures; you can use closures instead of constructor functions for simpler objects:

var baseFunction=function(message){
  return function(){
    console.log("Hello "+message);
  };
}

var world = baseFunction("World");
var op = baseFunction("OP");
world();//=Hello World
op();//=Hello OP

More on closures here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures

6 Comments

Could you use just new instead of Object.create if you don't use properties, or is there any other difference? Looking at your SpeakMessage.prototype.constructor=SpeakMessage; - I believe parent should not be aware of his childs in good design, although Javascript enables it.
@JanTuroň constructor is a property of prototype that comes with JS. var t=function();t.prototype.constructor===t;//true but because you set SomeConstructor.prototype=somethingElse you overwrite that value, that's why you repair it. Parent is not aware of it's Child but Child is of it's Parent. For easier refactoring you could use helper functions to set this up. I will add a bit to this answer stackoverflow.com/a/16063711/1641941 on trickyness that comes with.
@JanTuroň As for using new, it's not a good idea because Parent may have instance specific members that are put on Child's prototype with no use (best case they are shadowed when you do Parent.call(this) in Child body) stackoverflow.com/q/20915711/1641941. Another reason is that Parent may have time and resource consuming code that doesn't need to be called or can't be called (some checks can't be resolved without needlessly complicating your code). If Parent's body is empty I guess you can use it but may have to re do when you refactor Parent code
Wow! You wrote a book in that SO answer in your comment! I bet this is not the first time you've seen Javascript :-) Well done.
@JanTuroň Thank you, I find SO very helpful and wish it was there 12 years ago. When I'm trying to figure out something I end up writing it as an answer and hope others would improve, correct or bring it up to date.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.