Because syntax and control structures look very similar in classic OOP languages (Java, C#) to JavaScript, it can be easy for experienced developers to jump-in, make progress, and then shoot themselves in the foot due to misunderstanding core differences in underlying language design.
One of those core differences is how functions can function as objects with constructors.
In a classic OOP language, a class, constructor, and usage might look something like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
/* OOP =======*/ class Dog{ private String name; private int age; public Dog(String name, int age){ this.name = name; this.age = age; } } Dog myDog = new Dog("Buddy", 3); |
Although the syntax is similar, doing something like this in JavaScript will land you in a bad place:
|
1 2 3 4 5 6 7 8 |
/* JavaScript ==============*/ function Dog(name, age){ this.name = name; this.age = age; } var myDog = Dog("Buddy", 3); |
Scope
The first and most pressing issue is scope management. Look back up the the JavaScript example — The function used in place of a class, is just that: a Function. Whereas a custom class is a datatype, a template for data, our function is a function in the same way as this is a function:
|
1 2 3 |
function add(a,b){ return a + b; } |
Primarily, the problem is with the scope of the this keyword with in functions. Inside of a OOP language class, the this keyword refers to the parent object — the class that it is inside of. For example:
|
1 2 3 4 5 6 7 8 |
/* OOP =======*/ class Dog{ //... function string bark(){ return this.message; // *this* refers to the current instanciation of the Dog class } } |
However, in side of a JavaScript function, the this keyword refers to the global scope, or the window object. Thus:
|
1 2 3 4 5 6 7 8 |
/* JavaScript ==============*/ function Dog(){ //... this.bark = function(){ // *this* refers to window object return message; } } |
For the uninitiated, this can cause big problems. For example, consider:
A function/object Building, which contains the properties height, location, and occupancy, which are assigned like this: this.location = “123 N. 789 W.” Since the this keyword refers to the window object, your function has just overwritten window.location, the property used in changing the current location (url) of the page. Whoops!
But wait, there is a solution!
It is true, that a JavaScript object/function is really just a function — but you can create new instances of the function using the new keyword. Not only does the new keyword created a new instance (so you can have multiple objects of the same type on a page), but also assigns the scope of the this keyword to the function, NOT the window object. So, to use the previous example without clobbering the global scope:
|
1 2 3 4 5 6 7 8 9 10 11 |
/* JavaScript ==============*/ function Dog(){ //... this.bark = function(){{ // *this* refers to window object return message; } } var myDog = new Dog(); //*new* keyword controls scope myDog.bark(); |
However, if you have ever written a line of jQuery, you might be shaking your head in disagreement. Like you, I write something like this weekly:
|
1 |
var txtName = $("#name"); // no *new* keyword |
So, how does that work?
To make sure that jQuery object is allways called with the new keyword, it does it for you, every time. See the jQuery source constructor:
|
1 2 3 4 5 |
//jQuery.fn.constructor function (selector, context) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init(selector, context, rootjQuery); } |
So, each time $(“#asdf”) is used, jQuery returns a new jQuery.fn.init object. Now, keep in mind that this is one of several hundred lines within jQuery’s constructor source, but the key section for this subject. We can implement this method, with a few checks, in our code very easily.
Conclusion and template
So, to avoid clobbering the global scope, and to be convenient for implementers of your code, here is a well functioning JavaScript constructor template that can be implemented in your code:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function Dog(name, age){ if(this === window){ //if *this* is the window object, start over with a *new* object return new Dog(name, age); } this.name = name; //assign properties to the Dog, not the window this.age = age; this.bark = function(){ return "Woof!"; } } var myDog = Dog("Buddy", 3); myDog.bark() //Woof! |
See a demonstration of new keyword usage
Pingback: Convirtiendote.Pro Como crear una libreria en JavaScript