I am getting into ES6 lately and finally looking into classes seriously. I read that classes are just a cover over Objects in Javascript, however, I am finding the syntax most uncomfortable.
Could someone please explain / point to a reference where they explain, how classes simulate & importantly how we can map them into Javascript way of Object manipulation in our mind.
class NoteStore {
constructor() {
this.bindActions(NoteActions);
this.notes = [];
}
}
As per the example code above, I thought classes are mere constructors, but then what is a constructor doing within a constructor?
As someone who started learning programming with Js, I find the addition of classes (also React's classes) to be a terrible addition to Js so any help would be awesome.
Thanks
Classical class-based programming is based on defining a class which contains a constructor method and other methods which will be inherited by the constructed object. This is written as you show in your sample: the class is defined with its name, then contains a constructor function, then further functions.
The constructor method in a class definition is somewhat special, in that it gets invoked upon object construction. Since it's special, it somehow needs to be marked as such, and that's done by naming it constructor.
In classical Javascript (prototype-based OOP), this works differently: an object constructor is a simple function, and methods inherited by each object instance are defined on an object on the .prototype property of that function. There's nothing special about the constructor in prototype-based OOP, it's just a function, and the real magic lies in the new keyword and the use of this when the object gets constructed.
Expressing this in the form of a class with a constructor method is merely catering to classical-OOP developers, and arguably provides a more compact syntax.
class NoteStore {
constructor() {
this.bindActions(NoteActions);
this.notes = [];
}
bindActions(actions) {
..
}
}
This expressed in simple Javascript is:
function NoteStore() {
this.bindActions(NoteActions);
this.notes = [];
}
NoteStore.prototype.bindActions = function (actions) {
..
}
I think the explanation at MDN is quite clear.
class keyword is nothing but a new name for old style OOP implementation where we use a function constructor to get same functionality.
class keyword is brought to JavaScript to make it more similar to other traditional object oriented languages like C++, Java. But at core it is still function constructor with few changes.
For your question "what a constructor doing under constructor" ES6 has done some modification for older version so that class will not act as a constructor for examaple class cannot be invoked directly(without new keyword) like
NoteStore();
This will throw error in ES6 but if it was a function constructor like in ES5 than it works leaving you in a risk of bugs. classes are also not Hoisted.
For more detail and example you can read this link.
The JS class keyword:
Javascript has a system of inheritance which is called prototypal inheritance. This is a system were objects inherit properties from other objects. When a function is invoked using the new keyword the new object created with it 'inherits' properties from from the constructor function's prototype property.
The JS class keyword is merely syntactical sugar for a constructor function. The class keyword just has different syntax but it essentially achieves the same goal of Object creation with prototypes. Take for example the following snippet:
class human {
constructor (name) {
this.name = name;
}
speak () { console.log('hi')}
};
console.log(typeof human);
// logs function, a class is just a constructor function under the hood
const me = new human('Willem');
console.log(Object.getPrototypeOf(me) === human.prototype);
// logs true, the object me has a reference to the human.prototype object.
me.speak();
// This speak method is located on the prototype of the object, not the object itself
console.log(me.hasOwnProperty('speak')); // logs false
console.log(human.prototype.hasOwnProperty('speak')); // logs true
Related
I've been working on end to end test in testcafe and in their documentation I found following solution for Page Model:
class Page {
constructor () {
this.nameInput = Selector('#developer-name');
}
}
export default new Page();
I've been doing some research and I cannot get my head around why it is not resolved with an object literal:
export const Page = {
nameInput: Selector('#developer-name');
}
What are consequences of using each of them?
The difference is significant but fundamentally both are JavaScript objects, albeit with different properties and values. Listing all differences on the level of the language would be a long story and you'd be wise to read and understand on JavaScript prototype-based inheritance, but the most important differences are:
Page is a prototype object: whenever you create an object of class Page with new Page(), the constructor function is called with this referring to the object being created, not Page itself. Any property you access on the object is searched along the so-called "prototype chain", including the so-called prototype object. This prototype object can be accessed with Page.prototype and in fact, all methods you define in the class Page are also properties of this prototype object. Unlike own properties designed to refer to unique objects or primitives specific to an object, functions in JavaScript don't have to be bound to an object during object or function creation and can be shared between objects (belonging to the same class, for instance) and are called on the actual instance, not the prototype to which they may belong. In other words, this.nameInput in your constructor actually adds a property named nameInput to the object being created with new Page(), not the prototype, while the constructor itself (constructor) and any non-static methods you might add to Page will be added as properties of Page.prototype. The constructor is accessed as Page.prototype.constructor, by the way, as you'd naturally expect. Page.prototype.constructor === Page evaluates to true, by the way.
An expression of the form like { nameInput: ... } creates an object which prototype is Object.prototype, in practice the most basic form of object with "no prototype" and thus no superclass or any traits beyond what the fundamental object prototype object could provide. Any properties any such { ... } object may seem to have through its prototype chain, including methods, are properties of Object.prototype. This is why you can do ({}).toString() or ({}).hasOwnProperty("foobar") without actually having toString or hasOwnProperty properties in your object -- toString and hasOwnProperty are properties of Object.prototype referring to two distinct methods called toString and hasOwnProperty, respectively, and JavaScript creates a special property on your object called __proto__ referring to Object.prototype. This is how it knows how to "walk the prototype chain". The names of functions themselves do not matter like that, by the way -- I may add a property on an object referring to an anonymous function: var foo = ({}); foo.bar = function() { }; and call said unnamed function with foo.bar().
One mistake you appear to be making is confusing an object of a class with the class, otherwise you wouldn't compare export default class Page { ... } to export const Page = { nameInput: Selector(...) } -- the former creates a class accessible as Page which is used as the prototype object whenever objects of the class are created, while the latter creates an object accessible as Page which contains nameInput referring to result of evaluating expression Selector("#developer-name") (calling Selector with the sole argument "#developer-name"). Not the same thing at all, not to mention that former has Page refer to a class (invariably a prototype in JavaScript), while latter has Page refer to an object that does not seem to fit the pattern of a class.
The interesting things start when you realize that since a class is an object like any other in JavaScript, any object can be used as a class if you know how prototype-based inheritance works:
new (function() { this.nameInput = Selector("#developer-name"); })();
What happens here? You create a new object with an unnamed function as the object constructor. The effect is absolutely equivalent to otherwise creating the object with new Page with Page being your original ES6 class (ECMAScript 6 is the language specification that adds class syntax to JavaScript).
You can also do this, again equivalent to if you defined Page with class Page ...:
function Page() {
this.nameInput = Selector("#developer-name");
}
var foo = new Page();
Page.prototype will be the prototype object for foo, accessible as foo.__proto__ and otherwise making it possible for you to call instance methods on foo like foo.bar(), provided you define bar property on at least Page.prototype:
function Page() {
this.nameInput = Selector("#developer-name");
}
Page.prototype.bar = function() {
console.log(this.nameInput);
}
var foo = new Page();
foo.bar();
In fact, the above is what browser would do internally if it had to interpret the following code:
class Page {
constructor() {
this.nameInput = Selector("#developer-name");
}
bar() {
console.log(this.nameInput);
}
}
It is beyond the scope of my answer to list differences between the two last approaches (isn't the same thing as the two approaches you proposed), but one difference is that with class Page ..., Page is not a property of window in some user agents while with function Page ... it is. It's partly historical reasons, but rest assured that so far defining constructors and prototype using either approach is pretty much the same, although I can imagine smarter JavaScript runtimes will be able to optimize the latter form better (because it's an atomic declaration, and not just a sequence of expressions and statements).
If you understand prototype-based inheritance at the heart of all of this, all your questions about this will fall away by themselves as very few fundamental mechanisms of JavaScript support 99% of its idiosyncrasies. You'll also be able to optimize your object design and access patterns, knowing when to choose ES6 classes, when not to, when using object literals ({ prop: value, ... }) and when not to, and how to share fewer objects between properties.
Classes can be thought of as a blueprint, they both provide an object in the end. But as the object literals name implies, you literally create it there and then with this 'literal' syntax. A class however, we would use to instantiate new instances from 1 base blueprint.
let x = { myProp: undefined }
let y = { myProp: undefined }
x.myProp = "test";
y.myProp // undefined
Here we see we make two separate instances, but we will have to repeat code.
class X { }
let x = new X();
let y = new X();
A class does not need to repeat the code, as it is all encapsulated in the idea of what X should be, a blueprint.
Similar to above [in the literal] we have two separate instances but it's cleaner, more readable, and any change we wish to make to every instance of this 'X' object can now be changed simply in the class.
There's a plethora of other benefits and even a paradigm dedicated to Object-Oriented Programming, read here for more:
https://www.internalpointers.com/post/object-literals-vs-constructors-javascript
To go further into the constructor question... In other languages we have fields.
I believe when you assign a field in the constructor, it just creates an underthehood like field (I say underthehood like because JavaScript is prototype based, and the class syntax is syntactical sugar to help write prototypes easier for programmers familiar with class syntax in other languages).
Here is an example in C#.
public class X{
private int y;
X() {
this.y = 5;
}
}
It's more a convention to assign fields in the constructor in other languages, so I assume this has something to do with it in JavaScript.
Hope this helps.
By declaring it as a Class you can later identify what type of object it is with .constructor.name:
class Page {
constructor () {
this.nameInput = "something";
}
// No comma
anotherMethod() {
}
}
const pageClass = new Page();
const pageLiteral = {
nameInput: "something"
, // must have a comma
anotherMethod() {
}
}
console.log("Name of constructor for class: ", pageClass.constructor.name); // Page
console.log("Name of constructor for literal: ", pageLiteral.constructor.name); // Object
var A = function () {
this.someProperty = 0;
};
var a = new A();
The variable a is an object. What do I call to A? A class?
A is called a constructor function. Well, specifically, A is a variable that refers to a constructor function, but we don't usually get into that kind of mintuiae.
Sometimes people do call these "classes," because constructor functions aid in producing classes of objects (in the general sense, e.g., objects with common characteristics). But JavaScript doesn't have classes in the class-based OOP sense like Java or C#, it has a different inheritance mechanism called prototypical inheritance. (This is true even in ES2015 and beyond, where the keyword class is used to define a constructor function, the properties of the prototype it assigns objects when used with new, and sometimes properties on that function referring to other functions ["static methods"].)
The Javascript microlibrary augment.js is sometimes used to include OOP-like features in Javascript code. Despite working with Javascript on a daily basis I am still somewhat naive about the inner workings of the language, so I often rely on or borrow from patterns from other libraries to avoid pitfalls.
One function in the augment.js library is defclass, which is quite short:
augment.defclass = function (prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
};
My question is: how is this anything like defining a class? It looks like all it does is 1) set the prototype of the input's constructor to be the input itself, and then 2) return the constructor. What does that have to do with defining a class (or something like a class)?
A class defined like this:
var Thing = augment.defclass({
constructor: function () {
this.x = 5;
},
getX: function () {
return this.x;
}
});
A typical JavaScript constructor:
function Thing() {
this.x = 5;
}
Thing.prototype.getX = function () {
return this.x;
};
They both have the same effect, but the defclass version looks more familiar to users of other languages. One extracts the constructor from the prototype, and the other puts the prototype on the constructor.
how is this anything like defining a class?
The question you need to answer first is: What is a class in Javascript?
From: Object vs Class vs Function
As you must already be aware by now there are no classes in
JavaScript. Instead functions in JavaScript may be made to behave like
constructors by preceding a function call with the new keyword. This
is known as the constructor pattern.
From: JavaScript: The Good Parts Douglas Crockford, O'Reilly Media, 8 May 2008, page 29
If a function is invoked with the new prefix, then a new object will
be created with a hidden link to the value of the function's prototype
member, and this will be bound to that new object.
So again there are no classes - you have functions that can be invoked with new. If those functions have a prototype property, then the new objects created are inheriting from that prototype.
Everything you need to do to define a Javascript function to be used as a constructor is setting the properties you want instances to inherit on its prototype property and (as you pointed out in your question) augment.defclass is doing that.
The reason for having such a function has been already explained by minitech in his answer.
I think Javascript native OOP system is said to be classless, and is object-based, not class-based. But every example I see always start with a constructor similar to
function Person(name) {
this.name = name;
}
Just by using a constructor this way, doesn't this already imply a class is being used? (a class called Person)
Details:
If we can use
a.__proto__ = b;
on any Javascript platform, then I think it is classless. But we can't do that. If we want that behavior, we need to use
function F() { }
F.prototype = b;
a = new F();
and so, a constructor has to be used. So if constructor is such a cornerstone in Javascript, that means it is intended to be constructor of Person, Widget, etc, and these are classes.
The OOP in Javascript is slightly different from, for instance, the Java OOP.
The Javascript constructors do not refer to a class definition (so it is classless). Rather the constructor refers to a prototype. The base of the OOP in Javascript is the Object object (not the Object class), from where all the others objects are derived.
Prototyping grants you inheritance, and the possibility to extend an existing object with properties and methods.
I suggest you this article.
In your example:
function Person(name) {
this.name = name;
}
Mike = new Person('Mike');
the Person() function lets you create a new object prototyped on the Object object with a new property called name. Well, such a kind of function in Javascript oop is called a constructor.
Classless may be an inaccurate way to describe JavaScript's approach on OOP.
JavaScript does lack class definitions.
It also lacks a class-to-object correspondence.
You can't check if an object instantiated with a constructor such as Person is of class Person.
You can check if it contains the expected object members and conclude that it is of the expected class.
But if the object members have been changed along the way you're not going to get the desired/expected result.
TL;DR
JavaScript exposes constructors (appropriately named prototypes) as a manner in which you can define a template for constructing plain objects.
The important thing is that the end result of a prototype call is a plain object with some predefined members and not an object of a certain class .
It's good to think of javascript as a classless environment. If you think javascript classes you should be able to assume there's certain useful things you can do when there are classes and they're strictly enforced. However those certain useful things you cannot assume. The presence of something that looks like a constructor does not indicate you're creating a class.
For example, let's say you var dude = Person('Ashton Kutcher'). Now, when you dude instanceOf person, you get true. You assume you have the properties and methods of a person. What if some code comes along and says dude.personMethod = undefined. Now, while dude instanceOf person will still be true, the personMethod is no longer available.
You can think of javascript as having classes but it's a leaky abstraction. It's better to think of javascript as having a prototypal inheritance system when it comes to determining what something is and what you can expect of it.
More information here: http://javascript.crockford.com/prototypal.html
Create a class using the Object Constructor and prototyping can help us
in creating many instances of the class without redefining the object each time wee need it.
so in the above example
function Person(name)
{
this.name = name;
}
you can create two persons with different names.
example :
var personA = new Person();
personA.name = "james";
var personB = new Person();
personB.name = "Tom";
alert(personA.name + personB.name);
i suggest you reading this link will be helpful
http://www.javascriptkit.com/javatutors/oopjs2.shtml
I know there is a lot of similar questions are tons of great answers to this. I tried to look at the classical inheritance methods, or those closure methods etc. Somehow I consider they are more or less "hack" methods to me, as it doesn't really what the javascript is designed to do. (Welcome anybody correct me if I am wrong).
OK, as long as it works, I satisfy with the classical inheritance pattern like:
PARENTClass = function (basevar) { do something here; };
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen
// Inheritance goes here
CHILDClass = function (childvar) { do something; };
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement
// Instance
CHILDInstance = new CHILDClass(whatever);
Above is somehow, to my understanding the inheritance of JS. But one scenario I have no idea how to implement, is that what if I want to do some initializing DURING object creation (ie, within constructor), and the new object can be used right away.... My illustration on problem might not be too clear, so let me use the following C# Psuedo to explain what I want to do:
class PARENT {
public PARENT (basevar) { ... }
}
class CHILD : PARENT {
public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct.
{ ... }
}
For some reason (like init. UI elements), putting them in constructor seems the best way to do. Anyone have idea on how can I do it.
PS: in the *1, I have no idea what I should put there.
PS2: The above situation I DID found the jquery.inherit library can do, I just wonder if not using library can achieve it.
PS3: Or my understanding is wrong. Since javascript is not intended to mimick OOP (that's why i call it hack), what is the "CORRECT" logic to implement this.
It is not a hack as such; JavaScript is a prototyped language, as defined by Wikipedia as where:
..classes are not present, and behavior reuse (known as inheritance in class-based languages) is performed via a process of cloning existing objects that serve as prototypes.
As it says, classes are not used in JavaScript; each object that you create is descended from the JavaScript Object; all objects in JavaScript have the prototype object, and all instances of objects you create 'inherit' methods and properties from their object's prototype object. Take a look at the MDC prototype object reference for more information.
As of this, when you call the line:
CHILDClass.prototype = new PARENTClass();
This allows the CHILDClass object to add methods and properties to its prototype object from the PARENTClass object, which creates an effect similar to the idea of inheritance present in class-based languages. Since the prototype object affects every instance created of that object, this allows the parent object's methods and properties to be present in every instance of your child object.
If you want to call your parent class's constructor in your child class's constructor, you use the JavaScript call function; this allows you to call the parent class's constructor in the context of the child class's constructor, therefore setting the newly prototyped properties in your child class to what they are set as in the parent class.
You also do not need to put anything where you have specified the *1, since that line is merely used to add the methods and properties to the child class's prototype object; however, bear in mind that it calls the parent class's constructor, so if there are any arguments that are fundamental in the operation of the parent class constructor, you should check that these are present so as to avoid JavaScript errors.
You can manually invoke the parent constructor in the subclass constructor like this:
CHILDClass = function (basevar) {
PARENTClass.call(this, basevar);
// do something;
};
The trick here is using the call method, which allows you to invoke a method in the context of a different object. See the documentation of call for more details.
JavaScript has no built-in support for inheritance hierarchies as type extension is supposed to be done via aggregation, ie adding desired functionality directly to the object itself or its prototype if the property is to be shared between instances.
Nevertheless, JS is powerful enough to make implementing other forms of object construction possible, including classical inheritance.
Given a clone function - which is enough to add 'true' prototypical inheritance, and not JavaScript's bastardization thereof - your exampe can be implemented like this:
function ParentClass(baseVar) {
// do stuff
}
// don't overwrite the prototype object if you want to keep `constructor`
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
ParentClass.prototype.a = 'b';
ParentClass.prototype.c = 'd';
function ChildClass(childVar) {
// call the super constructor
ParentClass.call(this, childVar);
}
// don't inherit from a ParentClass instance, but the actual prototype
ChildClass.prototype = clone(ParentClass.prototype);
ChildClass.prototype.e = 'f';
It's also possible to add some syntactic sugar for class-based inheritance - my own implementation can be found here.
The example from above would then read
var ParentClass = Class.extend({
constructor: function(baseVar) {
// do stuff
},
a: 'b',
c: 'd'
});
var ChildClass = ParentClass.extend({
e: 'f'
});
I've got a lightweight javascript OOP wrapper that provides 'Class-like' inheritance where you can override base methods or call base constructors or members.
You define your classes like this:
//Define the 'Cat' class
function Cat(catType, firstName, lastName)
{
//Call the 'Animal' constructor.
Cat.$baseNew.call(this, firstName, lastName);
this.catType = catType;
}
//Extend Animal, and Register the 'Cat' type.
Cat.extend(Animal, { type: 'Cat' }, {
hello: function(text)
{
return "meaoow: " + text;
},
getFullName: function()
{
//Call the base 'Animal' getFullName method.
return this.catType + ": " + Cat.$base.getFullName.call(this);
}
})
//It has a built-in type system that lets you do stuff like:
var cat = new Cat("ginger", "kitty", "kat");
Cat.getType() // "Cat"
cat.getBaseTypesAndSelf() // ["Cat","Animal","Class"]
cat.getType() // "Cat"
cat.isTypeOf(Animal.getType()) // "True"
var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"])
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"]
dynamicCat.getFullName() // tab: fat cat
source code available at: Class.js
I also have more details in my blog post about OOP in javascript
Just thought I'd mention some of the issues with the classical pattern you're going for:
Reference vars on the super class(es) will be available as essentially statics on ALL instances. For example, if you have var arr = [1,2,3] in the super, and do instance_1.arr.push(4) instance_2.arr.push(5) ALL of these instances will "see" the changes.
So you solve 1. with Ayman's solution which Zakas calls "Constructor Stealing", but now you call the constructor twice: once for your prototype and once for the constructor stealing. Solution - for your prototype use a helper like inheritPrototype (I showed the whole implementation of this in this post: inheritPrototype method FWIW, this essentially came from a combination of page 181 of Zakas's book and some Crockford study.
No privacy (but then again, you'd need to use something like the Durable Object pattern to get this and that may not be what you want)
Object definition is left "dangling": Solution - put an if statement checking for any of your prototype's functions and then define the prototype with a prototype literal.
I have running examples of all of this on github!!!
It's been just as much of a challenge for me to truly grok both: Zakas and Crockford books on object creation and inheritance. I also needed to try some different JavaScript TDD frameworks. So I decided to create an essay on both TDD Frameworks and JavaScript Object Creation & Inheritance. It has running code and jspec tests! Here's the link:*
My GitHub Open Source Essay/Book