This JS new ROFLCOPTER


Published: 2014-09-27
Updated: 2014-10-04
Web: https://fritzthecat-blog.blogspot.com/2014/09/the-js-new-roflcopter.html


If you haven't yet been rolling on the floor laughing today, you could try this. Read the article, and then the comment below ...

If this didn't make you ROFL, go further and try to find out what's the meaning of Array.prototype.slice.call(arguments, 1). For that you could go to this. Try to understand the article, read the comments below ...

Still not ROFLING? You must be a JavaScript programmer :-) They've nothing to laugh anymore :-(

For me, I could not stop laughing about these "excellent" comments:

If you need stronger stuff, go to this site ...

But you're right, it is really serious. Failed communication is the root of all evil, or was it premature optimization?
Whatever, I must find out what happens when I call new in JavaScript. For anyone knowing that new is next to the C-language alloc(bytes), finding this out must be like receiving the >sign of the times<!

The JavaScript keyword "new"

First I try it with an Object as argument:

1
2
var someObject = {};
var someInstance = new someObject; // [object Object] is not a function

So this fails, new requires a function to be behind it.

1
2
3
4
var someFunction = function() {
console.log("Could it be that I am a constructor?");
};
var someInstance = new someFunction();

So, this worked, no error. But what is the return?

1
2
3
4
5
6
console.log("someInstance instanceof Object = "+(someInstance instanceof Object));
console.log("someInstance instanceof Function = "+(someInstance instanceof Function));

console.log("someInstance = "+someInstance);
console.log("someInstance.constructor = "+someInstance.constructor);
console.log("someInstance.prototype = "+someInstance.prototype);

This outputs:


someInstance instanceof Object = true
someInstance instanceof Function = false
someInstance = [object Object]
someInstance.constructor = function() {
console.log("Could it be that I am a constructor?");
}
someInstance.prototype = undefined

The created thing

Because we can not call new on Objects, it seems that classes are represented by functions in JavaScript.
To be able to distinguish between functions that create instances and such that do not, some wise people introduced the convention to write constructor-functions capitalized.

1
2
3
4
5
var Foo = function(a, b) {
this.A = a;
this.B = b;
};
var foo = new Foo(-1, 0);

Now before digging into the "this" keyword, here is a summary of the >sign of the times< (semantics that have gone into the C alloc() function). The new keyword ...

So keep in mind: when your "constructor" function returns an Object, THAT will be what the new operation returns! (And you are self responsible whether the instanceof operator works on it correctly.)

1
2
3
4
5
6
7
8
var Animal = function(givenName) {
return {
name: givenName
};
}

var animal = new Animal("Garfield");
console.log("animal instanceof Animal: "+(animal instanceof Animal));

This yields:


animal instanceof Animal: false

The JavaScript keyword "this"

When looking for explanations of the this keyword, you can find sentences like

Following code refers to the Foo constructor function above.

 1
2
3
4
5
6
7
8
9
10
11
12
var forgotNew = Foo(1, 2); // "this" is the "window" object

console.log("forgotNew="+forgotNew);
console.log("A = "+A);
console.log("B = "+B);

var appliedNew = new Foo(3, 4); // "this" is the object created by "new"

console.log("appliedNew.A = "+appliedNew.A);
console.log("appliedNew.B = "+appliedNew.B);
console.log("A = "+A);
console.log("B = "+B);

This outputs:


forgotNew=undefined
A = 1
B = 2
appliedNew.A = 3
appliedNew.B = 4
A = 1
B = 2
We see that Mind: by leaving out the new operator you create unintended global variables!

So the convention to write "constructor functions" capitalized gets some more sense. There should never be a constructor function call without a preceding new.

The "this" is an Object, I call it context. Functions are not bound to their objects. Sometimes we do not realize that context changes in JavaScript. Look at following example.

 1
2
3
4
5
6
7
8
9
10
11
12
var fooCapsule = {
Foo: function(a, b) {
this.A = a;
this.B = b;
}
};

fooCapsule.Foo(5, 6);
console.log("fooCapsule.A = "+fooCapsule.A);
console.log("fooCapsule.B = "+fooCapsule.B);
console.log("A = "+A);
console.log("B = "+B);

This outputs:


fooCapsule.A = 5
fooCapsule.B = 6
A = 1
B = 2
We can see that the global variables were not affected by that, still A=1 and B=2.

But imagine setting a "function pointer" to some encapsulated function and then calling it:

1
2
3
4
5
6
var myFoo = fooCapsule.Foo;
myFoo(7, 8);
console.log("fooCapsule.A = "+fooCapsule.A);
console.log("fooCapsule.B = "+fooCapsule.B);
console.log("A = "+A);
console.log("B = "+B);

This outputs:


fooCapsule.A = 5
fooCapsule.B = 6
A = 7
B = 8

We see that the globale A=7 and B=8 were affected now. Why? The function was called by a context that was not the Object the function was defined within. It was called from the browser's window Object, and thus it worked in that context.


This is another aspect of scoping in JavaScript:

And this is the reason why some JavaScript Gurus recommend to NOT use "this"!
Because it might be confusing, and functions called by a wrong context could do unintended damage.

When you don't use "this", you won't need "new". Both are not needed when using what I call "factory functions" to create Objects.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var fooFactory = function(a, b, context) {
if ( ! context )
context = {};

context.A = a;
context.B = b;

return context;
};

var fooBar1 = fooFactory(9, 10);
var fooBar2 = fooFactory(11, 12);
console.log("fooBar1.A = "+fooBar1.A+", fooBar1.B = "+fooBar1.B);
console.log("fooBar2.A = "+fooBar2.A+", fooBar2.B = "+fooBar2.B);
console.log("A = "+A);
console.log("B = "+B);

This outputs:


fooBar1.A = 9, fooBar1.B = 10
fooBar2.A = 11, fooBar2.B = 12
A = 7
B = 8
We see that the global variables A and B were not affected. And we created new Object instances without using the new operator. The only difference between new and creating Objects by {} is the "protoype" property, which is set by the new operator into the new Object. But this plays a role only when modelling inheritance hierarchies.





ɔ⃝ Fritz Ritzberger, 2014-09-27