COPYRIGHT © 2018 CodeStates
[library code] 
var carlike = function(obj, location) {
obj.location = location;
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = carlike({ }, 1);
amy.move();
var ben = carlike({ }, 9);
ben.move();

Let’s go one step further past the decorator pattern. Since the object we’re decorating is a brand new empty object, it seems like we could just ask the car-like function to build it for us. That’s where class comes in. The only difference between an object decorator and a class is that a class builds the object it’s augmenting, whereas decorators accept their target object as an input.

So, if we move the object creation into the car-like function

[library code] 
var carlike = function(obj, location) {
obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = carlike({ }, 1);
amy.move();
var ben = carlike({ }, 9);
ben.move();

and remove the obj function parameter in favor of declaring a local variable,

[library code] 
var carlike = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = carlike(1);
amy.move();
var ben = carlike(9);
ben.move();
COPYRIGHT © 2018 CodeStates
[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

we would have what’s known as a class and give it a different name to reflect that fact.

COPYRIGHT © 2018 CodeStates

A class is any construct capable of producing a fleet of similar objects that all conform to some interface. It’s conventional to name your class with a capitalized noun.

[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

The functions that produce these objects are called “constructors,” because their job is to construct objects that qualify as members of the class.

[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

The object that gets returned is called an “instance” of the class.

[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

Calling a construction function in order to build an instance (“( )”) is called “instantiating.”

This code is an example of the “functional class pattern.” But, JavaScript is a very flexible language. So, there are a number of different ways you could define a class and still have it work pretty much the same. Sometimes, coders coming from other languages take issue with calling this function a “class”, because it strikes them as too simple. In most languages, classes have a lot more complex language features supporting them. Even within the JavaScript community, you may hear claims that only certain complex styles of classes (which we will examine in upcoming slides) qualify as “real classes,” and that the style in this code is nothing more than a function. At the core, this is a semantic debate.

“Class” can be defined as “Any construct capable of producing a fleet of similar instances conforming to some interface.”

COPYRIGHT © 2018 CodeStates
[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = function( ) { obj.location ++ };
return obj;
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

The basic form of the functional class pattern results in duplicate methods. As with an earlier form of the decorator pattern, the line adding .move will run every time we call Car, and create a new function each time.

COPYRIGHT © 2018 CodeStates
[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = _________ obj ___________
return obj;
};
__________ = function() { _____. location++; };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

To avoid this, we’ll need to move the line that defines the function outside the body of the Car function. In this way, the interpreter will only visit it once (and only build one such function), rather than every time we invoke Car. But, if we move the function outside the constructor, it will no longer have closure scope access to the constructor’s obj variable, where the new instance we’re creating is stored.

[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = ________________________
return obj;
};
__________ = function() { this.location++; };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

In order for many instances to use it without an access to the closure scope that they were created in, we could use the argument “this.” The argument this provides the functionality for us by treating the object found on the left of the call-time dot as a function input and providing a name we can use to refer to it.

COPYRIGHT © 2018 CodeStates
[library code] 
var Car = function( location) {
var obj = { location : location };
obj.move = move;
return obj;
};
var move = function() { this.location++; };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

We could then assign obj.move to point to the same function stored in the global move variable. When we call the this argument inside the .move function on the last line as ben.move(), ben will be the binding target for this while the .move function is running.

[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, {move : move});
return obj;
};
var move = function() { this.location++; };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

“Extend” isn’t a native JavaScript function. But, it’s often made available to you by utility libraries like jQuery.

[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, {move : move});
return obj;
};
var move = function() { this.location++; };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
[utils.js]
var extend = function(obj1, obj2) {
for(var key in obj2) {
obj1[key] = obj2[key];
}
};

This syntax has exactly the same effect as manually copying properties with the “=” operator. JavaScript doe not duplicate objects when copying properties.

[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, {move : move, off : off, on : on});
return obj;
};
var move = function() { this.location++; };
var off = function() { ... };
var on = function() { ... };
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

But, if we refactor our code to include more and more shared methods, we have an issue. In the constructor, we’ll be forced to name more and more new properties we want added to the object. Since there’s no way to programmatically iterate over the variables in a scope, we’ll need to type out the name of each new function we add to our program in two places, which is error-prone.

COPYRIGHT © 2018 CodeStates
[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, methods);
return obj;
};
var methods = {
move : function() { this.location++; },
off : function() { ... },
on : function() { ... }
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

So, we could store all the methods we plan on adding to cars in an object to begin with in order to iterate over them programmatically.

[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, methods);
return obj;
};
var methods = {
move : function() { this.location++; },
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

To keep our example simple, we’ll display only one method. By the way, the name “methods” doesn’t make it clear that this object is closely related to the Car class. We could easily confuse it with methods containers for other classes.

[library code] 
var Car = function( location) {
var obj = { location : location };
extend(obj, Car.methods);
return obj;
};
Car.methods = {
move : function() { this.location++; },
};
[run.js]
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

Functions are just specialized objects. In addition to being invokable, functions are capable of storing properties just like any other object. It is important to note that there is no interaction between the properties of a function and how it will work when invoked. This is a simple property access created to declutter the methods object out of the global scope.

[Note] This blog post is written based on a lecture from CodeStates.

Thanks for reading! 💕 If you like this blog post, please clap👏

--

--