Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
175 views
Welcome To Ask or Share your Answers For Others

1 Answer

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):

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)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...