The code samples in your question reflect a couple of misunderstandings. Let me first turn to them:
- class is a reserved keyword in Javascript. You cannot use a class as the name of any variable or function. This is due not only to the fact that the Javascript language uses any keyword, but because it was planned for possible use in the future.
- There are no real classes in Javascript. What you may have seen is the different tastes of trying to simulate class inheritance using the available inheritance mechanism in Javascript, which is based on prototype objects, sharing properties with related instances.
- Very important: the prototype property used in this inheritance mechanism is set to a function , not directly to objects strong>
Douglas Crockford Quote in Chapter 5 JavaScript Inheritance : The Good Parts :
Instead of inheriting objects directly from other objects, an unnecessary level of indirection is inserted so that objects are created by constructor functions.
(...)
When a function is called using the constructor invocation template using the new prefix, this changes the way the function is executed.
Douglas Crockford then explains how the new operator can be implemented as a JavaScript function. This function uses several other functions defined in the book, so I rewrote it in a (somewhat) simpler form below:
function createNew(constructor) { // a function to explain the new operator: // var object = createNew(constructor); // is equivalent to // var object = new constructor(); // // param: constructor, a function // return: a new instance of the "constructor" kind of objects // step 1. create a new empty object instance // linked to the prototype of provided constructor var hiddenLink = function(){}; hiddenLink.prototype = constructor.prototype; var instance = new hiddenLink(); // cheap trick here: using new to implement new // step 2. apply the constructor the new instance and get the result var result = constructor.apply(object); // make this a reference to instance within constructor // step 3. check the result, and choose whether to return it or the created instance if (typeof result === 'object') { return object; } else { return instance; } }
In plain English, if you call new constructor() , where the constructor is a function, the operator creates a new object with a link to inherit the properties from the constructor, applies a constructor function to it, and returns either the value returned by the constructor or a new object if the constructor returned that something else that is not an object.
At any time before or after creating new instances using a custom constructor, you can change the prototype (object) in the constructor (function) :
function constructor(){}
Through a hidden link added to all objects created using this constructor (see the “cheap trick” in createNew), the properties of the prototype object can be accessed in all these instances, unless they are overridden by properties defined directly on the objects.
before.answer === Math.PI; // true after.answer === Math.PI; // true different.answer === "So long, and thanks for all the fish"; // true
Using this new knowledge, how would you create a new “class” of objects that inherit all the properties of arrays, along with the new empty () method, to remove all elements?
First , there are no classes in Javascript, so to create a new “class” I have to define a new constructor function. Let us call it CustomArray with capital C to follow the convention that constructor functions should start with capital.
function CustomArray(){}
Now I can create custom instances:
var myArray = new CustomArray();
Second , I want instances created with CustomArray to inherit Array properties:
myArray.prototype = new Array();
Third , I want all instances created using CustomArray to have an empty () method:
function empty(){
Finally , I can rewrite the entire example in a more concise way:
function CustomArray(){} CustomArray.prototype = []; CustomArray.prototype.empty = function(){ this.length = 0; }
Now I can create a custom array, set a couple of values and delete it:
var myArray = new CustomArray(); myArray[0] = "abc"; myArray[1] = "def"; myArray[2] = "ghi"; myArray.empty();
Problem : The above code is not working properly. What for? Since, unlike regular arrays, the value of the parameter in our custom array does not automatically increase the length property of the array. Similarly, calling empty () only sets the length property of our custom array to 0, it does not delete all the values inside.
In addition, we could not use the array literal syntax to initialize our custom array:
var myArray = ["abc","def","ghi"];
In general, it’s important to understand how Javascript inheritance works, but you can often find it less useful than expected, and there are simpler ways to achieve the same result, for example, using a builder instead of constructors. We can solve the problem using the builder customizeArray function to expand regular arrays:
function customizeArray(array){ array.empty = function(){ this.length = 0; }; } var myArray = ["abc","def","ghi"]; customizeArray(myArray); myArray.empty();
This code works as expected because myArray is a regular array in this case, expanded with a new method called empty. The main advantage and disadvantage of this approach compared to using prototypes is that it only modifies the selected instance, and if you worked with a large number of similar objects at the same time, setting this additional property will use more memory than setting one common property on a common prototype.
To avoid this, it may be tempting to directly modify the array prototype:
Array.prototype.empty = function(){ this.length = 0; }; var myArray = ["abc","def","ghi"]; myArray.empty();
This works, but I would advise him: you attach a custom property to each array instance, including all the code on your page created by these fancy libraries, plugins, frameworks, advertising and analytics scripts. Needless to say, this can break something in a place where you cannot fix it.
Edit: An interesting kangax blog post as a continuation: "How ECMAScript 5 still does not allow to subclass an array"