Subclass.prototype = new superclass () vs subclass = new superclass ()

I was subclassing in javascript using

object = new class () 

but I notice that some people create an instance using

 object.prototype = new class () 

Question: What is the difference? It seems to me that the latter respects the inheritance chain more, because if class () contains many operators this.variable = x , and the object is what you want to inherit from it, and not an instance of the class, you definitely assign these variables to the object prototype, and not for the object itself, as in the first case. So what is that?

 object = new class () |vs.| subclass.prototype = new superclass () 

However, are both functional in the program the same?

Side question: Also, I'm a bit unclear as to what the new operator actually does. It seems to me that I'm doing something like just creating an empty object and assigning the proto property to it?

+6
javascript
source share
3 answers

The difference is when you do:

 var subclass = new superclass(); 

an instance of superclass is created. subclass is just a variable. You do not create a subclass (i.e. do a subclass inherit superclass ). In the last example, assuming the subclass is a function, you say that all new instances of the subclass should inherit (i.e., the Subclass) superclass .

So:

 function superclass() {this.stuff="stuff";} function subclass() {} subclass.prototype = new superclass(); alert(new subclass().this); // pops up "stuff" 

is a prototypical inheritance.

As for the new operator, it is used to instantiate built-in objects and custom types. A custom type is just a function.

Edit: When I wrote above, this subclass inherits a supertype using prototypical inheritance, I mean that all new instances of the subclass inherit from one specific instance of the superclass, and not from the superclass type / function itself.

+5
source share

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(){} // the most simple constructor function: does nothing var before = new constructor(); var different = new constructor(); different.answer = "So long, and thanks for all the fish"; constructor.prototype = {}; // set an empty object to the prototype property constructor.prototype.answer = 42; // create a new property on prototype object constructor.prototype.answer = Math.PI; // replace an existing property var after = new 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(); // WRONG EXAMPLE: we must set CustomArray.prototype CustomArray.prototype = Array; // WRONG EXAMPLE: prototype expects an object, Array is a function CustomArray.prototype = new Array(); // OK, BUT: the simpler form [] should be used instead CustomArray.prototype = []; 

Third , I want all instances created using CustomArray to have an empty () method:

 function empty(){ // empty this array by setting its length to 0 // function to be called in the context (this) of an array this.length = 0; } CustomArray.prototype.empty = empty; // set the function named empty to the property "empty" of the prototype 

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"]; // this creates a regular array 

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"

+12
source share

Sharing a quick demonstration of Javascript inheritance after reading mozilla doc

 function Employee (name, dept) { this.name = name || ""; this.dept = dept || ""; } function Programmer (name, projs) { Employee.call(this, name, "programming"); this.projects = projs || []; } Programmer.prototype = new Employee; // demo dynamic inheritance Employee.prototype.leave = 10; var johnny = new Programmer("Johnny", ["C#","Java"]); alert("name: " + johnny.name + "\n" + "dept: " + johnny.dept + "\n" + "projects: " + johnny.projects + "\n" + "leave: " + johnny.leave); var mary = new Programmer("Mary", ["Javascript","Java"]); alert("name: " + mary.name + "\n" + "dept: " + mary.dept + "\n" + "projects: " + mary.projects + "\n" + "leave: " + mary.leave); alert("changing leave of all staff to 8"); Employee.prototype.leave = 8; alert("Johnny leave: " + johnny.leave); // 8 alert("Mary leave: " + mary.leave); // 8 alert("cannot batch move staff to another department"); Employee.prototype.dept = "sales"; alert("Johnny dept: " + johnny.dept); // programming alert("Mary dept: " + mary.dept); // programming 

Demo in jsfiddle Demo with lots of debugging in jsfiddle

+2
source share

All Articles