Reputation: 16299
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
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
Reputation: 10070
Following the author's logic:
using the
new
keyword ordinarily returns athis
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 new
ed, instead of returning an instance, will return a privately defined class that, when new
ed, 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
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
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