Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring a member function in JS

I've tried two ways to declare a member function in JS:

function init() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
}
a = new init();
a.displayName()

And

function init() {
    var name = "Mozilla";
    displayName = function() {
        alert(name);
    }
}
a = new init();
a.displayName()

The first method told me that displayName() is undefined. The way I see it a variable of type Function with name displayName is created, and thus it should work. Any one care to explain why it didn't work?

like image 912
Yotam Avatar asked Dec 04 '12 10:12

Yotam


People also ask

How do you declare a function in JavaScript?

A JavaScript function is defined with the function keyword, followed by a name, followed by parentheses (). Function names can contain letters, digits, underscores, and dollar signs (same rules as variables). The parentheses may include parameter names separated by commas: (parameter1, parameter2, ...)

What does () => mean in JavaScript?

It's a new feature that introduced in ES6 and is called arrow function. The left part denotes the input of a function and the right part the output of that function.

What are the 3 types of functions in JavaScript?

There are 3 ways of writing a function in JavaScript: Function Declaration. Function Expression. Arrow Function.


4 Answers

It doesn't work because that's now how JavaScript works. Just declaring a function within a constructor function doesn't set it up on the object created by the constructor function, you have to make the link between the object and the function explicitly (directly by assigning it to the object, or more often indirectly via a prototype).

The typical way you do that is via prototypical inheritance, although you can also just assign functions directly to individual objects (more below — but you talked about "member functions," and the typical way you do things like that in JavaScript is via prototypes).

There are a couple of ways to set up prototypical inheritance. The classic way, which is compatible with a broad range of JavaScript engines even in legacy browsers, is via the prototype property on constructor functions, which refers to an object. That object becomes the prototype of instances created via new FunctionName. You add properties to that object to share them amongst the instances created by that function.

So, using prototypical inheritance:

function Init(name) {
    this.name = name;
}
Init.prototype.displayName = function() {
    alert(this.name);
};

var i = new Init("Mozilla");
i.displayName();

Notes on the above:

  1. In JavaScript, the overwhelming convention is that constructor functions start with an upper case letter. So I called it Init rather than init.

  2. All functions automatically have a prototype property on them, which is a blank object.

  3. I add a property to that object called displayName which refers to a function.

  4. Rather than hard-coding the name, I pass it into Init as an argument.

  5. Note that I store the name on a property on the newly-constructed instance; within the call to Init, that instance is available as this.

  6. Similarly, because displayName is called as part of an expression retrieving the function reference from the object, this is the object within the call to displayName, and so this.name has the name.

  7. To keep things simple in the above, I assigned an anonymous function to displayName. (The property has a name, the function does not.) I tend not to do that in real code.

  8. All instances constructed via new Init will share the same copy of the displayName function, via the prototype.

More to explore (on my blog):

  • Mythical methods
  • You must remember this
  • Anonymouses anonymous

You might also be interested in my Lineage toolkit, if you're interested in building classes of objects in JavaScript (and hierarchies).

As of ES5, there's another option: Object.create. This allows you to create objects and assign them prototypes directly, without using constructor functions. But as you used new, which means you're using constructor functions, I won't go into detail on that.

Now, you don't have to use the prototype features of JavaScript if you don't want to. You can, for instance, do this:

function Init(name) {
    var name = name;

    this.displayName = function() {
        alert(name);
    };
}
var i = new Init("Mozilla");
i.displayName();

That doesn't use the prototype features of JavaScript, instead it just creates a new displayName function every time you call Init and assigns it directly to the object. (Any reasonable quality JavaScript engine will be smart enough to reuse the code of the function, but there will be distinct function objects for each instance). The above also makes the name property completely private, because the function we create on each call is a closure over the local variable name. (More: Closures are not complicated)

like image 106
T.J. Crowder Avatar answered Oct 03 '22 08:10

T.J. Crowder


To create something like a member function you need to add it to the protoype of the constructor function:

function init() {
    this.name = 'Mozilla';
}
init.prototype.displayName = function() {
    alert(this.name);
}

I also highly recommend you to read something about how the object system in JavaScript works. There's a pretty good article about it on MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript

like image 28
ThiefMaster Avatar answered Oct 03 '22 08:10

ThiefMaster


The following should work:

function Init() {
    var name = "Mozilla";
    this.displayName = function() {
        alert(name);
    }
}
a = new Init();
a.displayName()
like image 45
janith Avatar answered Oct 03 '22 10:10

janith


One of the standards you can use is

var init = (function() {

    var name = "Mozilla"; // Shared by all instances

    function init() {
        this.name = "IE"; // Spesific to the created instance                  
    }    

    init.prototype = {
        displayName: function() {
            alert(name);
            alert(this.name);
        }        
    }

    return init;

})();

var a = new init();
a.displayName();​
like image 39
Kodemon Avatar answered Oct 03 '22 08:10

Kodemon