I understand what is happening in the following snippet, and how to fix (with a binding or by making walk friend a method outside of the constructor), but why is this happening? It seems counter intuitive to me to have to bind a class' scope to its own methods.
class Person {
constructor(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk;
}
}
get name() {
return this._name.toUpperCase();
}
walk() {
console.log(this.name + ' is walking.');
}
}
let bob = new Person('Bob');
let bill = new Person('Bill', bob);
console.log(bob.name); // BOB
console.log(bill.name); // BILL
bill.walk() // Bill is walking.
bill.walkFriend(); // We expect 'BOB is walking', but we get 'BILL is walking.'
What's happening is that there is no intrinsic connection between a "method" in an ES2015 ("ES6") class and the instance, just like there isn't with the older style constructor functions.¹ friend.walk just returns a raw method reference, there's nothing about it that binds it to friend unless you do so yourself. Putting it another way, friend.walk === Person.prototype.walk is true. E.g., your counter-intuitive understanding is correct (except it's not about scope, but rather the value of this). :-)
Remember that the new class stuff is almost entirely just syntactic sugar (but, you know, the good kind of sugar). Your Person class almost exactly equates to this ES5 code:
var Person = function Person(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk;
}
};
Object.defineProperty(Person.prototype, "name", {
get: function() {
return this._name.toUpperCase();
},
configurable: true
});
Object.defineProperty(Person.prototype, "walk", {
value: function() {
console.log(this.name + ' is walking.');
},
writable: true,
configurable: true
});
You've said you know how to solve it, and indeed both of your solutions will work, either binding:
constructor(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk.bind(frield); // **
}
}
or creating walk within the constructor as an arrow function, instead of on the prototype:
constructor(name, friend) {
this._name = name;
this.walk = () => { // **
console.log(this.name + ' is walking.'); // **
}; // **
if(friend) {
this.walkFriend = friend.walk;
}
}
¹ There is an intrinsic connection between the method and the prototype of the class it's defined within, which is used if you use the super keyword within the method. The spec calls that link the [[HomeObject]] field of the method (but you can't access it in code, and it can be optimized away by the JavaScript engine if you don't use super in the method).
There are only 4 use cases of the this in JS. You might like to check this for a good read. In this particular case you have an instruction this.walkFriend = friend.walk; which refers to the walk function in the object passed in by the friend argument. It's neither a new function definition nor belongs to the object it resides in. It's just a referral to the function existing in the object referred as friend. However when you invoke it the this in the friend.walk function becomes the object from where it's been invoked. Hence you get the name property of the object referred by the this.
There are several ways to fix this. One as you would guess is bind. You can make it like this.walkFriend = friend.walk.bind(friend); or another is, to invoke it from within it's own scope like this.walkFriend = _ => friend.walk(); (I presume since you use classes arrows should also be fine with you.)
Related
How do I add properties to a constructor function in JavaScript? For example. If I have the following function.
function Hotel(name)
{
this.name = name;
};
var hotel1 = new Hotel('Park');
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this". Of course it would not be private since objects created will be able to use it correct?
Can I do something like this. Do I use the this keyword or do I use the var keyword
which one is it? I have example 2 on the function constructor on the bottom
1. var numRooms = 40;
2. this.numRooms = 40;
3. numRooms : 40,
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
};
I know that if I want a function within the object constructor I need to use the this word. Will that work as well for normal variables as I have asked above.
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
this.addNumRoomsPlusFive = function()
{
return this.numRooms + 5;
}
};
You can simple add a private variable to your constructor:
function Hotel(name) {
var private = 'private';
this.name = name;
};
But if you will use your Hotel function without a new operator, all properties and functions which was attached to this will become global.
function Hotel(name) {
var private = 'private';
this.name = name;
};
var hotel = Hotel('test');
console.log(name); // test
It is good idea to return an object in constructor function:
function Hotel(name) {
var
private_var = 'private',
private_func = function() {
// your code
};
retur {
name: 'name',
public_func: private_func
}
};
var hotel = Hotel('test');
console.log(name); // undefined
So if you will use Hotel constructor without new operator no global variable will be created. This is possible only if the return value is an object. Otherwise, if you try to return anything that is not an object, the constructor will proceed with its usual behaviour and return this.
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this".
Yes we can:
// API implementation in the library
function Hotel(name) {
// only our library code knows about the actual value
const numRooms = 'privateNoRoomsVar';
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// also, users don't have access to 'numRooms' variable so they can't use hotel[numRooms].
If a user looks at the source code and finds out the value privateNoRoomsVar, then they can misuse the API.
For that we need to use symobls:
// API implementation in the library
function Hotel(name) {
// no one can duplicate a symbol so the variable is really private
const numRooms = Symbol();
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// there is no way users will get access to the symbol object so the variable remains private.
Private class features, #privateField, are supported by all the browsers so we don’t have to worry about this anymore.
// API implementation in the library
class Hotel {
// private field
#numRooms = 40;
constructor(name) {
this.name = name;
}
addNumRoomsPlusFive() {
return this.#numRooms + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
//console.log('hotel.numRooms =', hotel.#numRooms); // throws error
Javascript historically creates objects from prototypes of other objects. It was a result of EMCA2015, that you have a distinct syntax of a class that specifies an object. As an aside, if you mouse over the table in that link it gives dates of when the feature was implemented.
A javascript object created by the new operator is more or less a combination of an associative array ( what you make with let avar={}; ) that can access the function level scopes it is defined in. The keys of the array are its properties. According to its creator, Javascript was created to be an easy to use program language without a hierarchy of types. One of the ways it accomplished this is by more or less considering its mapping type to be equivalent to the prototypical Object which object oriented programming languages describe.
Adding properties in 2022
function AProtoype(arg1, arg2, arg3){
//this defines a property
this.pa=arg1;
/* unicorns in this section */
let x = 1;
/*
a getter which has the same syntax as a property
but returns x from the scope which it references and
not the object.
*/
get getx() => x;
}
let object = new AProtoype(2,3,4);
Is equivalent to the following code for the purposes of data access but not inheritance and typing. The new operator also sets variables on an object that are used for these purposes.
function NewObject(arg1, arg2, arg3){
let prototype = {};
/*dragons in this section, as you are not using the this keyword to accomplish things*/
prototype.pa = arg1;
Object.defineProperty(prototype, "getx", {get:()=>x});
return prototype;
}
//If you do this instead of using the new operator it is an anti-pattern.
//And like all anti-patterns: "But it works!"
let object = NewObject(2,3,4);
The relevant property defining methods where in some sense supported as early as 2010, 2011. I do not have a contemporary source to that time to confirm if you could pull off what I'm doing though, and you'd only want to if all else failed and it needed to run on Internet Explorer 9. In the event all else is failing, you may want to read the documentation for Object.create, which is also of interest because more or less provides an api to make new objects.
Now, for a fun time and horror, you can also define a function that returns this, and get an object back with an equivalent binding of that function. The horror comes when it is an object in global scope, and you rename a property of that object; as Javascript will resolve the name collision by happily writing on whatever it finds if it can. You can then use this to re-implement the prototype pattern that javascripts new operator is built off of conceptually, for the sake of science.
When you use a "constructor function" in Javascript, any properties defined on the instance using the this keyword become public. This is unavoidable, because Javascript objects have no concept of private properties - if it exists, it can be accessed directly as object.property.
For example, if you tried to do as in the following snippet, mimicking a typical getter/setter pattern with a private variable in Java or C# (note that even if this worked, this is not idiomatic Javascript):
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
then while you can indeed use the getter and setter to do as you expect, you can also just access and set the private variable directly! Demonstration:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - not intended to work
console.log(obj.privateVar); // 2
obj.privateVar = 3;
console.log(obj.getVar()); // 3 (using public API to get it to show that the direct update to the private variable also affects the intended public methods)
There is though a way to mimic the effect of private variables. They're not actually object properties - because, as I have just demonstrated, such are intrinsically public - but the same can be mimicked by:
not using a "constructor function" at all, but a regular function that happens to return an object. This is all a constructor function really does, anyway - the difference in JS is only syntactic, that you do not need to use the new keyword when you call the function. (Although you still can, if you really prefer - any function that returns an object can be called with new and behave in the same way as without it, although performance will likely suffer a little as the function would then construct a brand new object and throw it away. See MDN for a justification of these statements, particularly step 4.)
inside this function, using a regular variable as the private variable. This variable will be completely inaccessible from outside by the simple rules of scope, but you can still have the returned object retain access to it by the "magic" of closures.
Here is the above getter/setter example translated to this procedure, as well as demonstrations of it working. (I hasten to add again though, that this wouldn't be considered idiomatic code in Javascript.)
function makeObjectWithPrivateVar(privateVar) {
function getPrivateVar() {
return privateVar;
}
function setPrivateVar(newVal) {
privateVar = newVal;
}
return { getPrivateVar, setPrivateVar };
}
var obj = makeObjectWithPrivateVar(1);
// getter
console.log(obj.getPrivateVar()); // 1
// setter
obj.setPrivateVar(2);
// getter again to observe the change
console.log(obj.getPrivateVar()); // 2
// but how could we access the private var directly??
// answer, we can't
console.log(obj.privateVar); // undefined
console.log(privateVar); // ReferenceError, privateVar is not in scope!
Note finally though that it's rare in modern Javascript to use the function-based constructors in this style, since the class keyword makes it easier to mimic traditional class-based languages like Java if you really want to. And in particular, more recent browsers support private properties directly (you just have to prefix the property name with a #), so the initial code snippet translated into a class and using this feature, will work fine:
class MyObject {
#privateVar
constructor(privateVar) {
this.#privateVar = privateVar;
}
getVar() {
return this.#privateVar;
}
setVar(newVal) {
this.#privateVar = newVal;
}
}
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - now doesn't work
console.log(obj.privateVar); // undefined, it doesn't exist
// console.log(obj.#privateVar); // error as it's explicitly private, uncomment to see error message
Usually it's performed using closures:
var Hotel = (function() {
var numrooms=40; // some kind of private static variable
return function(name) { // constructor
this.numrooms = numrooms;
this.name = name;
};
}());
var instance = new Hotel("myname");
In Javascript Koans, .beget() is used to, I suppose, allow a new prototype be created with identical traits? I'm hoping to clarify whether the Gonzo.prototype = Muppet.prototype.beget(); is what allows gonzo.answerNanny()); to work, or whether it's the Muppet.call(this, age, hobby);
function Muppet(age, hobby) {
this.age = age;
this.hobby = hobby;
this.answerNanny = function(){
return "Everything's cool!";
}
}
function Gonzo(age, hobby, trick) {
Muppet.call(this, age, hobby);
this.trick = trick;
this.doTrick = function() {
return this.trick;
}
}
Gonzo.prototype = Muppet.prototype.beget();
it("should be able to call a method on the base object", function() {
expect(this.gonzo.answerNanny()).toEqual("Everything's cool!");
});
The this.answerNanny function is a public priviledge function declared within the Muppet constructor. Since it's declared in the constructor and not on the Muppet.prototype then it's Muppet.call(this, age, hobby); that will add the answerNanny member to the Gonzo instance.
However, since the answerNanny function doesn't have to be priviledged (it doesn't access any variables that are private to the Muppet constructor) then it should really be defined on Muppet.prototype.
Finally, note that beget is not native JavaScript. I'm not sure to which implementation it refers here, but I believe it shall be similar to the one described by Crockford. The same can be achieved using Gonzo.prototype = Object.create(Muppet.prototype);
I have the following simple inheritence pattern and I would like to know if it's ok to call methods the way i do from within the constructor function (basically speaking, using this instead of "super prototype".
Parent class, Pet
function Pet(name) {
this.name = name;
this.nickname = name;
this.adopt();
}
Pet.prototype.adopt = function() {
this.nickname = 'Cutty ' + this.name;
}
Pet.prototype.release = function() {
this.nickname = null;
}
Pet.prototype.cuddle = function() {
console.log(this.name + ' is happy');
}
Subclass, Lion
function Lion(name) {
Pet.prototype.constructor.apply(this, arguments); // super(name)
this.cuddle();
this.release();
}
Lion.inherits(Pet);
Lion.prototype.adopt = function() {
// DTTAH
}
Lion.prototype.release = function() {
Pet.prototype.release.call(this);
console.log('Thanks for releasing ' + this.name);
}
inherits helper (polyfills are bad I know)
Function.prototype.inherits = function(Parent) {
function ProtoCopy() {}
ProtoCopy.prototype = Parent.prototype;
this.prototype = new ProtoCopy();
this.prototype.constructor = this;
}
My pets are instantiated like so var lion = new Lion('Simba')
In Lion constructor,
Can I keep using this when calling sub/parent class methods ? Or should I use methods from parent prototype directly ? (like pseudo call to super() or in release())
Reasons why I am asking are:
this substitution at runtime
constructor property not always what we are thinking (from what I read here and there)
I am not sure how these things can influence the resulting object.
Thanks for your enlightenment !
What is the difference between using this.fn() and MyClass.prototype.fn.call(this) in a constructor function?
This is not specific to constructor functions, it's the same in all functions (methods) that are called on instances.
Indeed there's not much difference apart from the character count when this.fn === MyClass.prototype.fn, and they would behave exactly the same. However, this assumption is not always true - this might not inherit from MyClass.prototype directly, but rather be a subclass instance, and that subclass might have overwritten the this.fn method.
So which one is correct? Both, in fact. If you know the difference, you can choose the appropriate one for your case. Other languages have different default expectations here, see also for calling static methods.
Notice that you cannot replace the class reference by this.constructor, which would be overwritten as well. In a reasonable setup1, this.fn() would be always equivalent to this.constructor.prototype.fn.call(this).
This is similar to the reason why super calls must explicitly reference the super class, and not depend on instance properties (such as this.constructor, this.super or anything similar).
1: Where this.fn is a usual method inherited from the prototype, not an own instance-specific one, and where every prototype has the .constructor pointing to the respective constructor whose .prototype it is.
Simplifying the problem, consider the following code in ES6:
class Pet {
constructor (name) {
this.name = name;
this.talk();
}
talk () {
console.log('My name is ' + this.name);
}
}
class Lion extends Pet {
constructor (name) {
super(name);
}
talk () {
super.talk();
console.log('I am a lion.');
}
}
would be equivalent to:
function Pet (name) {
this.name = name;
this.talk();
}
Pet.prototype.talk = function () {
console.log('My name is ' + this.name);
};
function Lion (name) {
Pet.call(this, name);
}
// inheritance:
Lion.prototype = Object.create(Pet.prototype);
Lion.prototype.constructor = Lion;
// override .talk
Lion.prototype.talk = function () {
Pet.prototype.talk.call(this);
console.log('I am a lion');
}
Running new Lion('Bobby') logs:
My name is Bobby
I am a lion
Further reading: http://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5
I don't understand in JavaScript when to use the word "prototype" vs. using simple "dot" notation without the word "prototype". Can someone look at these code blocks and help me understand when you'd want to use one over the other?
with "prototype":
function employee(name,jobtitle)
{
this.name=name;
this.jobtitle=jobtitle;
}
var fred=new employee("Fred Flintstone","Caveman");
employee.prototype.salary=null;
fred.salary=20000;
console.log(fred.salary);
without "prototype":
function employee(name,jobtitle,salary)
{
this.name=name;
this.jobtitle=jobtitle;
this.salary=salary;
}
var fred=new employee("Fred Flintstone","Caveman", 20000);
console.log(fred.salary);
JavaScript objects have a property which is a pointer to another object. This pointer is the object's prototype. Object instances by default share the same prototype:
function Employee(name){
this.name = name;
}
Employee.prototype.company = "IBM";
Employee.prototype.who = function(){
console.log("My name is", this.name, "I work for", this.company);
}
var bob = new Employee('Bob');
var jim = new Employee('Jim');
// bob and jim are seperate objects, but each is linked to the same 'prototype' object.
jim.who(); // jim doesn't have a property called 'who', so it falls back to it's 'prototype', where who exists
// My name is Jim I work for IBM
bob.who();
// My name is Bob I work for IBM
// Bob leaves IBM for Microsoft
bob.company = "Microsoft"; // bob now has a property called 'company'. The value of which is 'Microsoft', which overrides bob's prototype property of the same name.
bob.who();
// My name is Bob I work for Microsoft
Employee.prototype.company = 'Facebook';
jim.who();
// My name is Jim I work for Facebook
bob.who(); // Bob is not affected by the change.
// My name is Bob I work for Microsoft
delete bob.company;
bob.who(); // bob no longer has it's own property 'company', so like jim, it drops down to the prototype object.
// My name is Bob I work for Facebook
The issues around JS and inheritance may be complex, but the answer to your question is relatively simple. Consider this code:
function Klass() { }
var obj1 = new Klass();
var obj2 = new Klass();
Now, if you add a property to obj1, that property exists only on obj1. Likewise obj2.
If you add a property to Klass, that property likewise exists only on Klass (the function object). It doesn't affect obj1 and obj2 at all.
But if you add a property to Klass.prototype, that property will then be present on both obj1 and obj2, as well as any future objects created via new Klass. If you then change the value of the property on the prototype, the changed value will be what you see on all those objects.
You could add code inside the body of the Klass function to add properties to this; that will then cause any future Klass objects to get those properties. But each object would have its own copy - which can add up, memory-wise, especially when the properties are methods -and those copies would not be affected by future changes to the body of Klass.
ES5's Object.create almost removes the need to hassle around with .prototype anymore.
So, to pick up #Gerry's example, you can go like
var Mammal = {
walk: function() {}
};
var Dog = Object.create(Mammal, {
bark: {
value: function() {}
}
}); // create a new object which [[prototype]] refers to Mammal
Dog.walk();
Dog.bark();
The prototype object is a little tricky to understand; however this article on OOP JavaScript can help shed some light.
In a nutshell, the prototype object provides a blueprint for a 'recipient' object - all you have to do is point the recipient's prototype property at your blueprint object. Note that you can have as many recipients of a prototype blueprint object as you like (so Car and Train can both point to a common Vehicle prototype object).
You are free to define both properties and functions in a prototype object which will any recipient objects will be able to use, eg:
var vehiclePrototype = {
// A property which will be supplied to the recipient
cost: 0,
// A method which will be supplied the recipient
move: function () {
// Your prototype can refer to 'this' still.
console.log("Moving " + this.name);
};
}
You can now create a Car which makes use of the vechiclePrototype:
// Factory method for creating new car instances.
function createCar(name) {
// Define the Car's constructor function
function Car(name) {
this.name = name;
}
// Point the car's prototype at the vechiclePrototype object
Car.prototype = vechiclePrototype;
// Return a new Car instance
return new Car(name);
}
// Create a car instance and make use of the Prototype's methods and properties
var mustang = createCar(mustang);
mustang.cost = 5000;
mustang.move();
A new Train object could be created in a similar fashion:
function createTrain(whilstleSound) {
// Define the Train's constructor function
function Train(name) {
this.whilstleSound = whilstleSound;
}
// Point the train's prototype at the vechiclePrototype object
Train.prototype = vechiclePrototype;
// Return a new Train instance
return new Train(name);
}
var ic125 = new Train("pooop pooop");
ic125.move();
One of the big advantages of using Prototypical inheritance all instances of both Car and Train share the exact same move function (instead of creating multiple instances of the same function) which results in a significant memory saving if there are many instances of these objects.
Ignore new, ignore .prototype they are just confusing notions. If you really want prototypical inheritance use Object.create but most of the time inheritance is completely overkill. (prototypical inheritance should only be used as an optimization technique).
When building classes just create objects and extend them.
var Walker = {
walk: function() {}
}
var Eater = {
eat: function () {}
}
var Dog = extend({}, Eater, Walker, {
bark: function () {},
sniffBehind: function () {}
})
function dog(dogName) {
return extend({}, Dog, {
name: dogName
})
}
var steveTheDog = dog("steve")
console.log(steveTheDog.name === "steve")
Use any arbitrary arity extend function you want, _.extend, jQuery.extend, pd.extend, etc.
pd implements extend as follows
function extend(target) {
[].slice.call(arguments, 1).forEach(function(source) {
Object.getOwnPropertyNames(source).forEach(function (name) {
target[name] = source[name]
})
})
return target
}
With prototype, you can extend in a 'cleaner' way, because you are separating the logic inside your constructor function from the properties and methods that define your object.
var Mammal = function() { ... };
Mammal.prototype = {
walk: function() { ... }
};
var Dog = function() { ... };
for (var prop in Mammal.prototype) {
Dog.prototype[prop] = Mammal.prototype[prop];
}
Dog.prototype.bark = function() { ... };
However, the above without prototype could look like this:
var Mammal = function() {
this.walk = function() { ... };
};
var Dog = function() {
Mammal.apply(this);
this.bark = function() { ... };
};
This way of extending Objects is however made irrelevant by modern JavaScript libraries like Underscore.js, or could be written much cleaner with the help of for example jQuery too.
You could use the word prototype to define some functionality across the application for particular type (Array, Function, Number of custom type)
For example you can extend all arrays with property sum:
const arrayPrototype = Array.prototype
Object.defineProperty(arrayPrototype, 'sum', {
get() { return this.reduce((a,b) => a + b, 0) }
})
When you've executed the chunk of code, all arrays have the property:
console.log([1,3,-1,10].sum) // prints 13
According to this article it should be a Javascript 2.0 way to define class. However, I never saw that in practice. Thus the question. How to use class keyword and what is the difference between Javascript 1.x way of doing things?
I know this is a old post, but as of today i.e with the advent of ECMAScript 6 we can declare javascript classes.
The syntax goes as follows :
class Person{
constructor(name){
this.name = name;
}
printName(){
console.log('Name is '+this.name);
}
}
var john = new Person('John Doe');
john.printName(); // This prints 'Name is John Doe'
A complete guide to this can be found in this post
The reason you never saw the class keyword used in practice is that all the current implementations of JavaScript are 1.x.
JavaScript 2.0 was merged into ECMAScript 4 which was rather unpopular and so never made it into the real world.
So to answer your question, how do you use the class keyword? You can't.
Summary
In ES6 the class keyword was introduced. The class keyword is no more than syntactic sugar on top of the already existing prototypal inheritance pattern. Classes in javascript is basically another way of writing constructor functions which can be used in order to create new object using the new keyword.
Example
class Person {
constructor(name) {
this.name = name;
}
talk() { console.log('hi'); }
}
const me = new Person('Willem');
console.log(typeof Person)
// logs function, Person class is just another constructor function under the hood
console.log(me.__proto__ === Person.prototype)
// logs true, classes just use the same prototypal inheritance pattern which is used by constructor functions.
// An object created with the new keyword gets a __proto__ property on it which is a reference to the prototype property on a constructor function.
In the above sample there can be observed in the first log that classes create from the class keyword actually are functions under the hood.
console.log(typeof Person) // logs 'function'
es6 classes use the same prototypal inheritance pattern which is used by constructor functions. Here is another example to demonstrate this behavior:
class Dog {
constructor (name) {
this.name = name;
}
bark () { console.log('bark') };
}
let doggie = new Dog('fluffy');
doggie.bark(); // logs bark
Dog.prototype.bark = () => console.log('woof');
// changing the prototype of Dog, doggie refers to this with its __proto__ property.
//Therefore doggie bark method has also changed.
doggie.bark(); // logs woof
The takeaway in the above example is that the bark method of any dog instance can be changed at runtime. This is because the bark method of any object created with the Dog class is just referring to this function.
You never saw it in practice because virtually nothing supports JavaScript 2.0. That draft is from a specification that died before being anything other than draft.
You can still build classes in JS of course using prototype!
var foo = function() {
this.hurrah = "yay!";
return this;
}
foo.prototype.doit() {
alert(this.hurrah);
}
If you've a Java or C# background, here's how to define a class in JavaScript
var MyClass = function (f, l){//constructor
//private members
var firstName = f,
lastName = l,
fullName = function () { //fullName is a private function
return firstName + " " + lastName;
};
return {
//public members
getFullName: fullName
};
}
var output = document.getElementById('Output'); //<div id="Output"></div>
var myName = new MyClass("First", "Last");
output.innerHTML = myName.getFullName();
Just to add the ECMA5 way of class making.
Note that it does not have a constructor function this way (but you can trigger an init function if you like)
var Class = {
el: null,
socket: null,
init: function (params) {
if (!(this.el instanceof HTMLElement)) {
throw new Error('Chat room has no DOM element to attach on.');
}
return this.doStuff();
},
doStuff: function (params) {
return this;
}
};
var instanceofClass = Object.create(Class, {
el: {
value: document.body.querySelector('.what ever')
},
someMoreData: {
value: [0,5,7,3]
}
}).init();