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 nae displayName
is created, and thus it should work.
Any one care to explain why it didn't work?
Thanks
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
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:
In JavaScript, the overwhelming convention is that constructor functions start with an upper case letter. So I called it Init
rather than init
.
All functions automatically have a prototype
property on them, which is a blank object.
I add a property to that object called displayName
which refers to a function.
Rather than hard-coding the name, I pass it into Init
as an argument.
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
.
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.
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.
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)
The following should work:
function Init() {
var name = "Mozilla";
this.displayName = function() {
alert(name);
}
}
a = new Init();
a.displayName()
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();
In your first method:
function init() {
var name = "Mozilla";
function displayName() {
alert(name);
} } a = new init(); a.displayName()
function displayName(){} only can be called in init(), it's like private function, so can not be used as a public function of the object(init())