This question already has answers here:
ES6 - declare a prototype method on a class with an import statement
(3 answers)
Closed 5 years ago.
How can we use the class keyword in ES6 to add methods on the fly like we did in ES5?
https://jsfiddle.net/user1212/7c57eou3/
class Person{
constructor(name){
this.name = name;
}
getName(){
return this.name;
}
setName(name){
this.name = name;
}
}
function Company(cName){
this.cName = cName;
}
Company.prototype.getName = function(){
return this.cName;
}
How can Person have a new method added after the class has been defined?
You don't use the class keyword to add further methods. Just like in ES5, you simply assign them to the prototype object:
class Person { … }
…
Object.assign(Person.prototype, { // Object.assign provides a neater syntax
logName() { // but really is the same as Person.prototype.logName = …
console.log(this.name);
},
alertName() {
alert(this.name);
}
});
As others have answered your specific question, you'd use prototype
But just as a reminder, if you are modifying prototype of a class to add methods, maybe you want to use extends syntax and create a "subclass", so you always use the same class logic without touching prototype.
For most programmers that come from other languages is difficult to understand prototype-style classes, so if you could use ES6 only typical class style, I would say go for it. Like this:
class Hello {
constructor(name) {
this.name = name;
}
hello() {
return 'Hello ' + this.name + '!';
}
static sayHelloAll() {
return 'Hello everyone!';
}
}
class HelloWorld extends Hello {
constructor() {
super('World');
}
echo() {
alert(super.hello());
}
}
var hw = new HelloWorld();
hw.echo();
alert(Hello.sayHelloAll());
taken from here
Related
In my Javascript class Order, I have a static method and a non-static method, and they both contain the same code. If possible, how would one of these methods inherit the code from the other? This is an attempt to make my code look more readable since it's becoming quite unwieldy.
You can use classes and inheritance, create a parent class and then a subclass. The extends keyword makes the methods of the parent class available inside the child class.
The super keyword calls the constructor of the parent class.
//Parent class (superclass)
class Animal {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
}
//Child class (subclass)
class Cat extends Animal {
constructor(name, usesLitter) {
super(name);
this._usesLitter = usesLitter;
}
get usesLitter() {
return this._usesLitter;
}
}
const bryceCat = new Cat('Bryce', true);
console.log(bryceCat.name); //Output: Bryce
console.log(bryceCat.usesLitter); //Output: true
To create a static method you can use the static keyword. For example, generateName() you can call it directly from the class, but not from an instance of the class.
class Human {
constructor(name) {
this._name = name;
static generateName() {
const names = ['Angel', 'Pedro', 'Luis', 'Mario', 'Julio'];
const randomNumber = Math.floor(Math.random()*5);
return names[randomNumber];
}
}
console.log(Human.generateName()); // Returns a random name.
Is there any difference between the two methods of setting up a class in javascript:
Example 1:
class Friend {
constructor(name) {
this.name = name;
}
}
var friendOne = new Friend('John');
Example 2:
function Friend(name){
this.name = name;
}
var friendOne = new Friend('John');
Both of these examples create:
// Friend.prototype
// {constructor: ƒ}
So my question is related to what approach is best for creating class based inheritance with Javascript?
Thanks
I think there is no obvious differences for them.
compare with "Function" constructor, "class" just syntax sugar, more semantic.
Ok say we have this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
printName() {
console.log('this.name');
}
}
what I want to do is define printName, something like this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
// we want to define printName using a different scope
// this syntax is close, but is *not* quite correct
printName: makePrintName(foo, bar, baz)
}
where makePrintName is a functor, something like this:
exports.makePrintName = function(foo, bar, baz){
return function(){ ... }
};
is this possible with ES6? My editor and TypeScript is not liking this
NOTE: using ES5, this was easy to do, and looks like this:
var Car = function(){...};
Car.prototype.printName = makePrintName(foo, bar, baz);
Using class syntax, currently the best thing that is working for me, is this:
const printName = makePrintName(foo,bar,baz);
class Car {
constructor(){...}
printName(){
return printName.apply(this,arguments);
}
}
but that is not ideal. You will see the problem if you try to use class syntax to do what ES5 syntax can do. The ES6 class wrapper, is therefore a leaky abstraction.
To see the real-life use case, see:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L171
the problem with using TestBlock.prototype.startSuite = ..., is that in that case, I cannot simply return the class on line:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L67
The preferable ways to do this in JavaScript and TypeScript may differ due to limitations in typing system, but if printName is supposed to be a prototype method and not instance method (the former is beneficial for several reasons), there are not so many options.
Prototype method can be retrieved via accessor. In this case it should be preferably memoized or cached to a variable.
const cachedPrintName = makePrintName(foo, bar, baz);
class Car {
...
get printName(): () => void {
return cachedPrintName;
}
}
And it can be lazily evaluated:
let cachedPrintName;
class Car {
...
get printName(): () => void {
return cachedPrintName || cachedPrintName = makePrintName(foo, bar, baz);
}
}
Or it can be assigned to class prototype directly. In this case it should be additionally typed as class property because TypeScript ignores prototype assignments:
class Car {
...
printName(): () => void;
}
Car.prototype.printName = makePrintName(foo, bar, baz);
Where () => void is the type of a function that makePrintName returns.
A way that is natural to TypeScript is to not modify class prototypes but extend prototype chain and introduce new or modified methods via mixin classes. This introduces unnecessary complexity in JavaScript yet keeps TypeScript happy about types:
function makePrintNameMixin(foo, bar, baz){
return function (Class) {
return class extends Class {
printName() {...}
}
}
}
const Car = makePrintNameMixin(foo, bar, baz)(
class Car {
constructor() {...}
}
);
TypeScript decorator cannot be seamlessly used at this point because class mutation is not supported at this moment. The class should be additionally supplemented with interface to suppress type errors:
interface Car {
printName: () => void;
}
#makePrintNameMixin(foo, bar, baz)
class Car {
constructor() {...}
}
Just replace : with =
printName = makePrintName()
: goes for type notation.
Edit
As noted in comments the above will not change the prototype. Instead, you can do this outside the class definition, using ES5 syntax:
// workaround: extracting function return type
const dummyPrintName = !true && makePrintName();
type PrintNameType = typeof dummyPrintName;
class Car {
// ...
printName: PrintNameType;
}
Car.prototype.printName = makePrintName();
Playground
Another idea I haven't seen mentioned yet is to use a method decorator. The following decorator takes a method implementation and puts it on the prototype, as desired:
function setMethod<T extends Function>(value: T) {
return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {
descriptor.value = value;
delete descriptor.get;
delete descriptor.set;
};
}
Put it in a library somewhere. Here's how you'd use it:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
#setMethod(makePrintName(foo, bar, baz))
printName() {} // dummy implementation
}
The only downside is that you have to put a dummy implementation of the method with the right signature in the class, since the decorator needs something to decorate. But it behaves exactly as you want at runtime (it isn't an instance method which costs a new function definition for each instance, or an accessor which costs an extra function call at each use).
Does that help?
Why don't you try something like this
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
this.printName = makePrintName(foo, bar, baz);
}
}
am I dont getting it or ..??
class keyword normally is just a syntax sugar of the delegate prototype in ES5. I just tried it in typescript
class Car {
private kind: string;
private name : string;
printName :Function;
constructor(name) {
this.kind = 'Car';
this.name = name;
}
}
var makePrintName = function (foo, bar, baz) {
return function () { console.log(foo, bar, baz); };
};
Car.prototype.printName = makePrintName('hello', 'world', 'did you get me');
var bmw = new Car('bmw');
bmw.printName();
console.log(bmw.hasOwnProperty('printName'));
In an ES6 class with some instance variables and methods, how can you add a mixin to it? I've given an example below, though I don't know if the syntax for the mixin object is correct.
class Test {
constructor() {
this.var1 = 'var1'
}
method1() {
console.log(this.var1)
}
test() {
this.method2()
}
}
var mixin = {
var2: 'var2',
method2: {
console.log(this.var2)
}
}
If I run (new Test()).test(), it will fail because there's no method2 on the class, as it's in the mixin, that's why I need to add the mixin variables and methods to the class.
I see there's a lodash mixin function https://lodash.com/docs/4.17.4#mixin, but I don't know how I could use it with ES6 classes. I'm fine with using lodash for the solution, or even plain JS with no libraries to provide the mixin functionality.
Javascript's object/property system is much more dynamic than most languages, so it's very easy to add functionality to an object. As functions are first-class objects, they can be added to an object in exactly the same way. Object.assign is the way to add the properties of one object to another object. (Its behaviour is in many ways comparable to _.mixin.)
Classes in Javascript are only syntactic sugar that makes adding a constructor/prototype pair easy and clear. The functionality hasn't changed from pre-ES6 code.
You can add the property to the prototype:
Object.assign(Test.prototype, mixin);
You could add it in the constructor to every object created:
constructor() {
this.var1 = 'var1';
Object.assign(this, mixin);
}
You could add it in the constructor based on a condition:
constructor() {
this.var1 = 'var1';
if (someCondition) {
Object.assign(this, mixin);
}
}
Or you could assign it to an object after it is created:
let test = new Test();
Object.assign(test, mixin);
In es6 you can do this without assigning and you can even invoke the mixin constructor at the correct time!
http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/#bettermixinsthroughclassexpressions
This pattern uses class expressions to create a new base class for every mixin.
let MyMixin = (superclass) => class extends superclass {
foo() {
console.log('foo from MyMixin');
}
};
class MyClass extends MyMixin(MyBaseClass) {
/* ... */
}
You should probably look at Object.assign(). Gotta look something like this:
Object.assign(Test.prototype, mixin);
This will make sure all methods and properties from mixin will be copied into Test constructor's prototype object.
I'm surprised to find that none of the answers mentions what I would consider a mixin in the sense of composition (and in contrast to inheritance), which to me is a function that adds functionality to an object. Here's an example making use of both inheritance and composition:
class Pet { constructor(name) { this.name = name } }
class Cat extends Pet { expression = 'miaow' }
class Dog extends Pet { expression = 'bark' }
class Human { constructor(name, age) { this.name = name; this.age = age; } }
class American extends Human { expression = 'say howdy' }
function canSayHello(...contexts) {
for (const context of contexts) {
context.sayHello = function() {
console.log(`Hello my name is ${this.name} and I ${this.expression}`)
}
}
}
canSayHello(Pet.prototype, Human.prototype); // apply the mixin
const garfield = new Cat('garfield');
const pluto = new Dog('pluto');
const joebiden = new American('Joe Biden', 79);
garfield.sayHello();
pluto.sayHello();
joebiden.sayHello();
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();