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.
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
.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With