I need do add a method to a Javascript class using the new syntax. I tried this way:
class X{
constructor() {
this.a = 'b'
}
x(){
}
}
X.prototype.y = function (){
console.log('y')
}
var x = new X()
x.y()
console.log(X) // print the the class but not the new method.
It just prints:
class X{
constructor() {
this.a = 'b'
}
x(){}
}
But I expected
class X{
constructor() {
this.a = 'b'
}
x(){}
y(){
console.log('y');
}
}
How could I add a new method to a Javascript class?
this works fine, if you are checking this in google chrome console, then please check by expanding proto node.
or alternatively try checking
console.log(X.y)
or console.log(X.prototype.y)
or console.log(x.y)
this must print that function
There are two major ways to add methods to a class, this can be within the scope of the class when writing the code or using ".prototype" to attach a method to your class.
Below is an example of adding a method within the class scope:
class Person {
constructor(fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
sayName = function() {
return `My Name is ${this.firstName} ${this.lastName}`
}
}
const firstPerson= new Person ("Thor", "Odinson")
console.log(firstPerson.sayName())
And below an example of a method creation from outside the scope of a class using a prototype:
class Person {
constructor(fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
}
Person.prototype.sayName = function() {
return `My Name is ${this.firstName} ${this.lastName}`
}
const secondPerson= new Person ("Tony", "Stark")
console.log(secondPerson.sayName())
A very important thing to note is that using prototype to add a method to a class doesn't change the structure of the class. So logging the object won't render the method. But the method is available to all subclasses and instances of that class.
I know it's a bit late, but would this have solved your problem back then?
class XWithY extends X {
constructor() {
super()
}
y() {
console.log('y')
}
}
const xwy = new XWithY();
console.log(xwy instanceof X); // outputs true
You can use Object.setPrototypeOf.
Example:
// A class…
class Someone {
constructor(qui){
this.qui = qui
}
}
// A mixins with new methods
class MyMixins {
says(quoi){
console.log(this.qui + " says "+ quoi)
}
eats(quoi){
console.log(this.qui + " eats "+quoi)
}
}
// An instance…
const marion = new Someone("Marion")
// This fails…
//marion.says("hello!")
//marion.eats("potatoes")
//-----> Here's the trick <------
Object.setPrototypeOf(Someone.prototype, MyMixins.prototype);
// This pass…
marion.says("hello!") //=> "Marion says hello!"
marion.eats("potatoes") //=> "Marion eats potatoes"
Related
I am attempting to define a class called "User"... then further along in the code I am trying to add a method to the class by writing to "prototype".
I'm not sure if my terminology is correct here... though I would like to have the method "who_auto" available to all future instances of "User"...
Trying out this code in JSFiddle... is giving me the error message:
"Uncaught TypeError: pp.who_auto is not a function"
Here's my code:
class User {
constructor(name) {
this.name = name;
this.chatroom = null;
}
who() {
return `I am ${this.name}`;
}
}
User.prototype = {
who_auto: function() {
console.log(`
Hello, I am ${this.name}
`);
}
}
const pp = new User('peter parker');
console.log(pp);
console.log(pp.who());
pp.who_auto();
You overwritten the prototype instead of adding a property to the prototype. Below codes works.
class User {
constructor(name) {
this.name = name;
this.chatroom = null;
}
who() {
return `I am ${this.name}`;
}
}
User.prototype.who_auto = function() {
console.log(`Hello, I am ${this.name}`);
}
const pp = new User('peter parker');
console.log(pp);
console.log(pp.who());
pp.who_auto();
Basically I want to use First.showName class' method in context of Second class, but have no idea how to access it.
class First {
constructor(){
this.elem = document.createElement("br");
}
showName = function (){
console.log('Name of the node:',this.elem.nodeName);
}
}
class Second {
constructor(){
this.elem = document.createElement("div");
}
showName = First.showName.bind(this); // error!
showName = First.prototype.showName.bind(this); // error!
showName = First.__proto__.showName.bind(this); // error!
}
window.testObject = new Second();
testObject.showName();
Let's put aside the element part for now and focus only on JavaScript.
Your First class has a method. But classes in JavaScript are just syntactic sugar over prototypes. So:
class First {
showName() { console.log(this.name); }
}
is the same as:
function First() {
}
First.prototype.showName = function() { console.log(this.name); };
So, basically, we want to take that function from the prototype of the class First. There are several ways to do this.
An easy way would be to extend the prototype of the second class:
class First {
showName() { console.log(this.name); }
}
class Second {}
Second.prototype.showName = First.prototype.showName;
const node = new Second();
node.name = 'Second has a name now.';
node.showName();
Another way would be on instantiation:
class First {
showName() { console.log(this.name); }
}
class Second {
constructor() {
this.showName = First.prototype.showName;
}
}
const node = new Second();
node.name = 'Second node.';
node.showName();
After that, it should be easy to adjust the contents of the function as you see fit.
Edit: after some comments on the question, here's also a gist of a composable way to do the same:
const showName = function showName() { console.log(this.name); }
class First {}
class Second {}
First.prototype.showName = showName;
Second.prototype.showName = showName;
const node = new Second();
node.name = 'Second name.';
node.showName();
The method declaration is wrong, should be:
myMethod() {
}
Do it the right way and create a base class for common methods and properties and inherit any class which will share these properties from it:
class Base {
constructor(){
this.name = "";
}
showName(){
console.log('Name of the node:', this.name);
}
}
class First extends Base {
constructor(){
super();
this.elem = document.createElement("br");
this.name = this.elem.nodeName;
}
}
class Second extends Base {
constructor() {
super();
this.elem = document.createElement("div");
super.name = this.elem.nodeName;
}
}
window.testObject = new Second();
testObject.showName();
That's OOP as it's best and not XGH.
Reference
class A{
constructor(name){
this[name] = name ; //to be private so i need this
new B(this);
}
getName(){
return this[name];
}
}
class B(){
constructor(a){
a.getName()// I wants to be like this
}
}
I just want to call the methods without creating a new instance.
If you want to make private data in a class, either use a WeakMap or a closure. this[name] is not private at all, it's completely visible to anything that has access to the instantiated object.
Another problem is that with your return this[name];, the getName function does not have the name variable in scope.
Also, an object's class methods can't be accessed before the object itself is instantiated.
You might want something like this instead:
const A = (() => {
const internals = new WeakMap();
return class A {
constructor(name) {
internals.set(this, { name });
}
getName() {
return internals.get(this).name;
}
}
})();
class B {
constructor(a) {
console.log(a.getName())
}
}
const a = new A('bob');
const b = new B(a);
How to detect whether EcmaScript class has its own constructor?
See code snippet below.
class Person {
constructor(name, age) { // <- Own constructor
this._name = name;
this._age = age;
}
}
class Manager extends Person {
// This class does not have it's own constructor
}
It seems there is no clear way to do this check.
Thank you all for time and help.
It's not bulletproof, but you could convert the constructor to a string, and see if it contains the word constructor( or something similar
function hasOwnConstructor(instance) {
var str = instance.constructor.toString();
return /class(.*?[^\{])\{([\s\n\r\t]+)?(constructor[\s]+?\()/.test(str);
}
class thing1 {
method() { return this; }
}
class thing2 {
constructor(argument) { return this; }
}
var ins1 = new thing1();
var ins2 = new thing2();
console.log( hasOwnConstructor(ins1) ); // false
console.log( hasOwnConstructor(ins2) ); // true
False positives could still be possible, but the regex makes the check quite strict, so it's not very plausable.
Inspect the constructor function.
class Example {
constructor(prop1, prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
}
You can pass parameters to your class via the constructor function that establishes properties which can be globally referenced when creating a new instance.
This line would pass int 1 and "test" as values to prop1 and prop2:
const exampleVar = new Example(1, "test");
and might render something like:
<Example prop1=1 prop2="test" />
Hope this helps. If it has a constructor function, there is a constructor, if it does not have the constructor function, then there is no constructor.
I'm trying do define a simple class called Mail using the new ECMAScript 2015 JavaScript classes as defined here.
I came up with this constructor and tried the following getter:
class Mail {
constructor(sender, date, subject, text) {
this.sender = sender;
this.date = date;
this.subject = subject;
this.text = text;
}
get sender() {
return this.sender;
}
}
But when I tried to use that method, it didn't work.
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender());
Returned:
TypeError: mail.sender is not a function
So, my doubt is:
Is it necessary to define getters and setters like in Java or can I simply access field like mail.sender (or so)?
If it is necessary, how to properly define getters and setters to each of class instance variables?
getter and setter are basically hooks to capture get- and set- actions for properties of an object. They are functions, but they seem (to the code that uses this Object) like a property.
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender); //no brackets
and if you add a setter, main.sender = "#foo.bar".
And I'm wondering that your code didn't get stuck in an infinite recursion, since your getter called itself.
class Mail {
constructor(sender, date, subject, text) {
this._sender = sender;
this._date = date;
this._subject = subject;
this._text = text;
}
//this IS `this.sender`!
//it should not `return this.sender`, since this would call this getter again,
//and you get stuck in an infinite recursion.
get sender() {
return this._sender;
}
//and a possible setter, that handles
//instance.sender = whatever;
set sender(value) {
this._sender = value;
}
}
Edit:
Does this mean that I can just ignore get and set methods because I can directly access object field?
you don't need getter or setter to make any property public in JS, simply defineing this property makes it public available. JS works the other way around, you have to take additional efforts to make things private (see closures). In JS everything is by default public.
But you can use getter (and setter) to fulfil additional tasks, like:
class Person{
constructor(firstName, lastName){
//regular public properties
this.firstName = firstName;
this.lastName = lastName;
}
//a composed value, that you can access like a property
get fullName(){
return this.firstName + " " + this.lastName;
}
//you could also add a setter like this
set fullName(value){
[this.firstName, this.lastName] = value.split(/\s+/g);
}
}
var john = new Person("John", "Doe");
console.log(john.fullName);
To use getters and setters, you just need to use and set the property. in your case: mail.sender. This will call the getter if you are using the value, or the setter if you are overriding the current value.
class Mail {
constructor(sender) {
this._sender = sender;
}
get sender() {
return "Sender: " + this._sender;
}
set sender(val) {
this._sender = val.toLowerCase();
}
}
const m = new Mail("TEST");
console.log(m.sender); // => "Sender: TEST"
m.sender = "TEST";
console.log(m.sender); // => "Sender: test"
Note that I used _sender to store the value to prevent a Maximum call stack size exceeded error.
You can use the property like any other property, and it will automatically call the getter or setter.
If what you were looking for is encapsulation, you could design your classes like so:
const Mail = (function() {
let sender; // this is "private"
return {
title: "public", // This is public
get sender() {
return sender;
},
// ...
};
});
In this case, you would then create new Mail objects like so:
const mail = Mail();
You could return a function in the Mail function in order to be able to instantiate new objects with the new keyword.
You actually did more than you need to. You don't need getters as you specified.
Try this:
class Mail {
constructor(sender, date, subject, text) {
this.sender = sender;
this.date = date;
this.subject = subject;
this.text = text;
}
}
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender);
JavaScript has no concept of classes.
The class keyword is just syntactic sugar.
What a class do is, it generates a constructor function for you.
const Person = class { // or `class Person`
constructor(name) {
this.name = name;
}
say(msg) {
return `${this.name} says: "${msg}".`;
}
}
That's exactly the same, what you will achieve with the following code.
const Person = function(name) {
this.name = name;
};
Person.prototype = {
say(msg) {
return `${this.name} says: "${msg}".`;
}
};
If you need private variables, you have to work with closures.
const Person = class { // or `class Person`
constructor(name) {
this.getName = () => name;
this.setName = (newName) => {
name = newName;
}
}
say(msg) {
return `${this.getName()} says: "${msg}".`;
}
}
let p = new Person('me');
console.log(p.name); // undefined
console.log(p.getName()); // 'me'
p.setName('he');
console.log(p.getName()); // 'he'
console.log(p.say('something')); // 'he says: "something".'
I advice you to not use class and to avoid new.
If you need an object, you simply can use factory functions:
const Person = function(name) {
let person = Object.create(Person.prototype);
person.name = name;
return person;
};
Person.prototype = {
say(msg) {
return `${this.name} says: "${msg}".`;
}
};