Problem

Whats wrong with this and new?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//problems with this and new

var thing = (function () {
this.a = 'hi'; // works
})();

var thing = (function () {
"use strict";
this.a = 'hi'; // breaks because we didn't use "new" so we don't have a "this"
})();

var thing = new (function () {
"use strict";
this.a = 'hi'; // works because we have a "this" because we used "new"
})();

So if you use this trying to stricten up your code is error prone,
once you stricten up your code you’ll have to remember to use new when constructing things that use this.

1
2
3
4
5
6
7
8
9
10
11
12
13
// problems with this

var thing = {
word: 'hi',
talk: function() {
return this.word;
}
};

thing.talk() // hi
var thingTalkFunc = thing.talk;
thingTalkFunc(); // cannot read property word of undefined (this is set to window)
thingTalkFunc.call(thing); // technically works

The problem is that this means “whatever object your function is attached to when its called”
people don’t usually expect that and it leads to huge amounts of bugs.
I see people many popular frameworks like Backbone, Angular and Ember suggesting patterns requiring this.
I also see people doing all sorts of things to get around this, like iterating over an objects functions and binding them all to it creating a lot of boilerplate (coffee script).

Proposed Solution: avoid this and avoid new

example OOP style:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

var someNamespace = (function () {
"use strict";
var self = {};

self.Animal = function (animalType, name) {
var animalSelf = {};

// public constructor
animalSelf.construct = function (animalType, name) {
type = animalType;
animalSelf.name = name;
return animalSelf;
};

// private var
var type = 'human';
// private function
function getTalkingPrefix() {
return type + ', ' + animalSelf.name + ': ';
}

//public var
animalSelf.name = 'lee';
//public function/method
animalSelf.talk = function (words) {
return getTalkingPrefix() + words;
};


// constructor is called at the end so when its called
// animalSelf has all the variables and functions attached
return animalSelf.construct(animalType, name);
};

self.Duck = function (name) {
var duckSelf = self.Animal('Duck', name);

duckSelf.talk = function (words) {
//optional argument
if (typeof words == "undefined") {
words = 'quack quack';
}
return 'duck says: ' + words
};

return duckSelf;
};

return self;
})();

var peppaPig = someNamespace.Animal('pig', 'peppa');
peppaPig.talk('Hi'); // "pig, peppa: Hi"

var daffyDuck = someNamespace.Duck('daffy');
daffyDuck.name; // "daffy"
daffyDuck.talk(); // "duck says: quack quack"
var talkingFunctions = [peppaPig.talk, daffyDuck.talk];
talkingFunctions[0]('Hi'); // "pig, peppa: Hi" // still works! yay!
talkingFunctions[1](); // "duck says: quack quack"

pros

No problems with this being lost and no boilerplate to bind this, doesn’t need new

Beginners don’t need to understand the complexities of this.

No framework required.

Interoperable with other frameworks e.g. instead of using Backbone.Collection.extend({ ... })

1
2
3
4
5
6
7
8
9
10
11

BroadbandMap.Collections.Networks = function () {

var self = new Backbone.Collection();

self.model = BroadbandMap.Models.Network;

self.url = '/api/1.0/networks';

self.parse = function (response) {
...

private classes are easy too e.g. var Duck instead of self.Duck

cons

This doesn’t support protected variables (ones that only subclasses can access) (arguably a plus).

You could have package private (vars in the outer scope) and public things by adding to self.
but adding package private vars and funcs in this outer scope could make it difficult to break out this file into smaller files.

You can override a method with one of a different signature, you probably shouldn’t do that,
in this case words is now an option argument to duck.talk which is probably fine,
but overriding a function(y, x) with a function(x, y) would lead to bugs.

The style may look unusual to people as most frameworks suggest using this

ES6

classes use this so we will still see lots of bugs related to its complexity.
Luckily for us even more complexity is added around this because the ES6 arrow functions will be forever bound to the this from the context it was created in.
This behaviour is simpler in that this isn’t going to change on you but using the this from the calling context may confuse some people:

1
2
3
4
5
6
7
var thing = {
word: 'hi',
talk: () => {
return this.word;
}
};
thing.talk() // undefined because this == window when the arrow function was created and window.word is undefined

At-least we won’t have so many libraries implementing inheritance differently and we will have a boilerplate-less constructor which has access to the methods when called.

One small benefit in ES6 is type checking that new must be used with a constructor.

1
2
3
4
class C {
m() {}
}
new C.prototype.m(); // TypeError: m() {} is not a constructor

shimming ES6 to bind methods so that they hold onto this
es6 arrow functions and this

conclusion

in general extension/inheritance is a complicated pattern,
to use an object you need to understand its type hierarchy and all the ways that can affect its behaviour
Its best to favour typical object composition with simple functions with inputs and outputs rather than closure’s and global state.
This is because it has less state (you might inherit things you don’t want).
Using this contrived example, why does a duck have a name or use words if all it does is quack? why is it an animal? a quacking function probably suffices.

“classical inheritance is obsolete talk”

It is also easier to unit test because using mocks for some objects in the class hierarchy can be difficult
(you may want to use mock objects to test some code interacts with other parts correctly without having to test those parts too).

Generally using inheritance is good when you know that the subclass really is a subtle variation of the “default behaviour” in the parent class and they will normally want to share lots of behaviour,
don’t feel bad if you don’t use inheritance and still treat objects interchangeably based on them having the same properties/methods (duck typing).

Beware the complexities of this!

Let me know what you think! Could it be improved? Are there any pros and cons that i have missed?