larryq
larryq

Reputation: 16299

Not understanding use of new keyword in Javascript

The code snippet below is from 'Javascript Web Applications' by O'Reilly. In it, the author explains that using the new keyword ordinarily returns a this context, unless you specifically return something else-- below, he's returning ' a function that would set up a new class', in his words (pg 7):

var Class = function(){
    var klass = function(){
        this.init.apply(this, arguments);
    };
    klass.prototype.init = function(){};
    return klass;
};

var Person = new Class;

Person.prototype.init = function(){
    // Called on Person instantiation
};

// Usage:
var person = new Person;

I'm not following this. What does returning klass do here? in the case of var Person = new Class, am I not getting a new Class object, but rather, some function that can create a Class? That's what I'm reading from the text but it's confusing to me.

Upvotes: 6

Views: 2102

Answers (4)

stackoverflow
stackoverflow

Reputation: 1587

Actually, here var Person = new Class; the new keyword is used only to fire the Class function, so basically you could use like this var Person = Class(); and it will have the same result

Upvotes: 0

Passerby
Passerby

Reputation: 10070

Following the author's logic:

using the new keyword ordinarily returns a this context, unless you specifically return something else

If he/she is correct, then the following code:

var Class = function(){
    var klass = function(){
        this.init.apply(this, arguments);
    };
    klass.prototype.init = function(){};
    return klass;
};

Does not define a "class" class; instead, it defines a "base" that, when newed, instead of returning an instance, will return a privately defined class that, when newed, will be guaranteed to run the init() method (this.init.apply(this)).

By that manner, when

var Person = new Class;

you are creating a new class named Person, that follows the constraints and behaviors (if any) defined as klass, inside Class (kind of look like extend/inherit in "real" OOP).

So the following code

Person.prototype.init = function(){
// Called on Person instantiation
};

is actually defining a "constructor" for class Person.

Edit:

Sorry for not coming up with proper words and sentences yesterday. I'm bad at expressing.

If you're comfortable with OOP, you can imagine that, Class is rather an interface/abstract/virtual class, and when you new Class, instead of creating an instance, you're rather extending/inheriting/implementing the behavior privately/virtually defined inside Class.

The klass.prototype.init=function(){}; kind of like a JS's way of abstract/virtual function, and by combining this.init.apply(this), you can, at may level, imagine it a constructor.

Upvotes: 1

LetterEh
LetterEh

Reputation: 26696

Before getting where he's going, the first step is getting this.

There are three things this can typically point to. If you have a function which is a property of an object:

var Bob = {
    name : "Bob",
    say  : function () { console.log(this.name); }
};

Bob.say(); // "Bob"

In this case, this points to whatever object owns the property (whatever is one-dot ahead, at the exact moment the function is called)

var say = Bob.say; // passing the function to a variable
var Sam = { name : "Sam" };
Sam.say = Bob.say; // passing the function to an object's property

say(); // undefined -- not what you were expecting
Sam.say(); // "Sam"

So this is decided at the last possible second.

Functions also have properties of their own, like objects.
Two of these are functions called .call and .apply and they allow you to run the function, but tell the function exactly what this is.

Remember how say(); didn't work on its own?

var say = Bob.say;
say.call(Bob); // "Bob" -- hooray!

The next part of this is the one we're most used to in object-oriented languages; using this along with new to make a new instance of a class:

var Person = function (name) {
    this.name = name;
    this.say = function () { console.log(this.name); };
};

var bob = new Person("Bob");
bob.say(); // "Bob"

Basically, inside of this constructor function (or any function, as constructors aren't special in JS), the function starts by checking if new was called.
If it was, set this to a brand new object, regardless of whether it's part of an object:

var Creatures = {};
Creatures.Person = Person;

Creatures.Person("Bob"); // `this` === Creatures
Creatures.name; // "Bob" -- whoops
var bob = new Creatures.Person("Bob");
bob.say(); // "Bob", yay!

So it's like the function is saying if (new) { this = {}; } at the top of the function.

I said there were three possibilities.
The third is that this === window
If you use a function where this isn't an object (either through call/apply, or as a property of an object) and new was not used to make a new object, then this points at window.
That is why say(); did not work on its own, before; window.say(); is the equivalent.

Back to new for a second -- new does a couple of other things.
Namely, it sets the value of the object's constructor:

var bob = new Person();
bob instanceof Person;  // true

It also gives objects made from that constructor access to the prototype object, which all instances share.

So now, look at what's going on inside of Class/Klass:
We're creating a new Class(); object.
Inside of the Class function, this = {}; (because of new).
Then, we're making a new "constructor" function, klass.

Then, we're setting the prototyped init function, which we .apply to any new this (in the klass, at the time a new instance is called).

Then we're returning the klass.

klass is actually what you're calling when you make a new Class

And when you call for a new object of a class, klass is being run.

Hope that helps with new and this and .call and Class/klass.

Upvotes: 7

mwoods79
mwoods79

Reputation: 1648

In javascript the new keyword implicitly returns this.

When you have function Foo () {} and apply new Foo, under the hood javascript does this function Foo () { return this; }. He is overwriting the way javascript's new works by explicitly returning a different object (the klass object).

Look at this example.

function Foo () { this.name = "foo"; };

function Bar () {
    return new Foo; 
};

var bar = new Bar;  // bar is now a Foo, because of the explicit return.

bar.name //=> 'foo'

If you can follow that you can follow what he is doing.

When you say var Person = new Class, it is actually returning the klass function and storing it in the Person variable (pointer).

Upvotes: 3

Related Questions