I am trying to access the name defined in the constructor via a method, but it is returning undefined. Here is the simple code:
class Person {
constructor(){
let name = 'Tom';
}
logName(){
console.log(this.name);
}
}
let x = new Person();
x.logName();
You need to define the name as a property of the object. In your case this.name
class Person {
constructor(){
this.name = 'Tom';
}
logName(){
console.log(this.name);
}
}
let x = new Person();
x.logName();
In your code, you've defined the variable name inside the constructor. It remains in there but doesn't escape.
Related
If we declare a class like this:
class client{
constructor(name){
this.name = name
}
get name()
{
return this.name ;
}
set name(val)
{
this.name = val ;
}
}
Instantiate
it will give an error ( too much recursion) and that normal because the setter will call itself.
class client{
constructor(name){
this.name = name
}
get name()
{
return this.name ;
}
set name(val)
{
this.name = val ;
}
}
let cl = new client();
But when i declare 'name' as class field i don't get that error, I don't understand why.
class client{
name = null ;
constructor(name){
this.name = name
}
get name()
{
return this.name ;
}
set name(val)
{
this.name = val ;
}
}
let p = new client();
console.log(p) ;
TL;DR You can't have both a data property and an accessor property with the same name on the same object, and if you have a data property on an object, any property with the same name on its prototype won't be used (unless you do so explicitly). The name class field definition creates an own data property on the object being constructed.
In the first case (as I think you know), this.name inside the name setter calls the name setter again, recursing until you run out of stack. (And the same for the getter, if you used it.)
So what's different when you have that name field definition there?
The way class fields are defined, that name definition creates an own property on the instance being created, as though you had this code at the beginning of the constructor (just after a super call if this were a subclass):
constructor(name) {
// Definition of `name` field:
Object.defineProperty(this, "name", {
value: undefined,
writable: true,
configurable: true,
enumerable: true,
});
// Remainder of constructor code:
this.name = name;
}
Since it's an own property, this.name resolves to that data property, not to the accessor property on the prototype that the get name and set name accessor definitions create. So those accessors on p's prototype are never used.
You can see that if you look at the definition of the property in your second example:
class client {
name = null;
constructor(name){
this.name = name;
}
get name()
{
return this.name ;
}
set name(val)
{
this.name = val ;
}
}
let p = new client();
console.log(p) ;
console.log(Object.getOwnPropertyDescriptor(p, "name"));
If you want to have the accessor property, you could use a private field, which is quite new but supported in modern environments:
class Client {
#name = null;
constructor(name) {
this.#name = name;
}
get name() {
return this.#name;
}
set name(val) {
this.#name = val;
}
}
let p = new Client("Joe");
console.log(p.name);
console.log(Object.getOwnPropertyDescriptor(p, "name")); // undefined
console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(p), "name")); // accessor
.as-console-wrapper {
max-height: 100% !important;
}
I have two classes. I want to access type property of Parent from instance:
// Parent class
function Animal() { this.type = 'animal' }
// Child class
function Rabbit(name) { this.name = name }
// I inherit from Animal
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit; // I want to keep Rabbit constructor too
// I instantiate my Rabbit and am trying to access rabbit.type
const rabbit = new Rabbit('Bunny');
rabbit.name // => Bunny
rabbit.type // => undefined. WHY?
I know how to solve it and access type, but...
// all is the same
// Child class
function Rabbit(name) {
Animal.apply(this, arguments); // Just need to add this line in Rabbit class
this.name = name
}
// all is the same
rabbit.name // => Bunny
rabbit.type // => animal
...but why it doesn't work in the first example? Is it possible to achieve it without using Animal.apply?
Yes, if you would add type to the prototype:
Animal.prototype.type = "animal";
Or you could hide the Animal.apply call behind the class sugar:
class Animal {
constructor() {
this.type = "animal";
}
}
class Rabbit {
constructor(name) {
super(); // <<<
this.name = name;
}
}
Rabbit.prototype = Object.create(Animal.prototype); only extends the properties defined in the prototype chain. The properties defined within the constructor won't get extended.
Try this,
...
Rabbit.prototype = new Animal();
...
Updated Example:
// Parent class
function Animal() { this.type = 'animal' }
// Child class
function Rabbit(name) { this.name = name }
Rabbit.prototype = new Animal();
Rabbit.prototype.constructor = Rabbit;
const rabbit = new Rabbit('Bunny');
console.log(rabbit.name);
console.log(rabbit.type);
I was learning JavaScript oops with some sample example when I came across to access superclass methods in subclass which is possible with super keyword
but when I try to access or return a variable of super class it returns undefined or the sub class variable I tried in various way to get variable
I have also gone this Stack Overflow post.
class dad {
constructor(name) {
this.name = name;
}
printname() {
console.log(this.name);
var a = 2;
return a;
}
sendVal() {
console.log(this.name);
var a = 2;
return this.name;
}
}
class son extends dad {
constructor(name) {
super(name);
}
printname() {
console.log(super.printname());
}
printvariable() {
console.log(super.name);
}
getvalue() {
console.log(super.sendVal())
}
}
var o1 = new dad('jackson');
var o2 = new son('jack')
o1.printname()
o2.printname()
o2.printvariable()
o2.getvalue()
When you use super.fieldName to access a field of a parent class, you are actually querying the field name on the prototype of the parent class.
So you might believe calling super(name); from the Son constructor sets the name in the prototype of the parent class, but it is not so, it actually sets the name property inherited by the Son class which you can access by using this.name.
So I modified your example code and shown how to actually get a value by calling super.fieldName. In the example I added a property age in the prototype of the Dad class and set its value to 50, now in the Son class printvariable() will correctly call the super.age by referring the prototype of the Dad class.
You can actually see it in action if you use babel to transpile it to ES2015, after all classes in JavaScript are actually syntactic sugar.
class Dad {
constructor(name) {
this.name = name;
Dad.prototype.age = 50; //adding property to prototype
}
printname() {
console.log(this.name);
var a = 2;
return a;
}
sendVal() {
console.log(this.name);
var a = 2;
return this.name;
}
}
class Son extends Dad {
constructor(name) {
super(name);
}
printname() {
console.log(super.printname());
}
printvariable() {
console.log(`super.name will be undefined, as not present in prototype of the Dad class: ${super.name}`);
console.log(`super.age will have a value of 50, present in the prototype of the Dad class: ${super.age}`);
console.log(`this.name will be jack, as it is set from the constructor of the Son class: ${this.name}`);
}
getvalue() {
console.log(super.sendVal());
}
}
var o1 = new Dad('jackson');
var o2 = new Son('jack')
o1.printname();
o2.printname();
o2.printvariable();
o2.getvalue();
I am experimenting imitating OOP like behavior in JS. I am trying to have (private) variables: id and name in function Person. To this function I am passing arguments which are used to initialize (private) variables. Then I am returning object having getter and setter for name and only a getter for id, thus effectively making id read-only.
So id can be set only through constructor whereas name can be set and get anytime.
This is the code:
var Person = function (_id,_nm) {
var id, name;
this.id = _id;
this.name = _nm;
return {
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
document.writeln("Id: "+id+"<br />Name: "+name);
}
}
}
var person = new Person(123, "Mahesh");
person.print();
However when new Person(123,"Mahesh") executes, I dont understand it is actually setting id and name or not, since while debugging I can see values set appropriately when hovered over them but Locals panel does not show them initialized:
Or either while in print() is is not referring to the desired id and name variables:
Whats wrong here?
Working fiddle
The reason is because you are using public members for the Person.prototype. You don't need to add this references to these two. So delete:
this.id = _id;
this.name = _nm;
and simply use:
var id = _id,
name = _nm;
Now everything will work fine. The whole idea is to use var, and not this, otherwise a closure will not be created. Now you will not be able to access name and id directly, instead you will have to use setName(), getName(), setId(), getId() etc.
The two members, id and name, will now become closures as you want them to be.
Update
If you used this.id, then it wouldn't have been private and you could just do var p = new Person(1, "Mahesha"); and access p.name or p.id directly. They are supposed to be private so this is not what you want.
With the closure pattern, p.name and p.id are undefined and can only be accessed through p.getName(); and p.getId();. Read on how closures work. The idea is that because you are using that var name, a closure will be created to remember it's value.
Your getName and setName are using that closure to access the name property. There is no this.name, there is a value remembered through a higher - order closure.
this.id and var id are not the same. this.id is a property of the object. var id belongs to the local scope.
Either use new or return a value. Not both.
The problem is that you're creating a new instance of Person using the new keyword, but your constructor function is returning another object instead.
When you return something from a constructor function it returns that value, and not the instance of the function.
You see when you execute new Person(123, "Mahesh") a new instance of Person is created. This is accessible within the constructor function as this.
If you don't return anything from your constructor then JavaScript automatically returns this. However you're explicitly returning another object.
No wonder var person doesn't have id and name properties (which you only defined on this).
In addition print doesn't display the id and name because although you declared them (var id, name) you didn't give them any values. Hence they are undefined.
This is how I would rewrite your Person constructor:
function Person(id, name) {
this.getId = function () {
return id;
};
this.getName = function () {
return name;
};
this.setName = function (new_name) {
name = new_name;
};
this.print = function () {
document.writeln("Id: " + id + "<br/>Name: " + name);
};
}
I didn't set the id and name properties on this because it makes no sense to include them.
You've mixed up using locally scoped ("private") variables for _id and _nm and "public" instance properties (this.id and this.nm).
In this case you need the former, but you created both and only initialised the latter.
Note that since id is read-only you don't really need a separate local variable at all, you can just use the lexically scoped first parameter to the constructor:
var Person = function (id, _nm) {
var name = _nm;
...
};
Let me try to explain using the following:
// Scope 1
var Person = function (_id,_nm) {
// Scope 2
var id, name;
this.id = _id;
this.name = _nm;
return {
// Scope 3
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
$("#output").append("<p>Id: "+id+"; Name: "+name + "<p/>");
}
}
}
The print method will return undefined because you are referring to the var id, name; that is never set in your code. You set the _id and _name to the property id and name but you fail to return the object that you just created. Instead, you return a dictionary, that references the name and id variable you created in Scope 2 that you never set, hence the undefined output in the print() call.
Here is what you should have done:
var NewPerson = function (_id,_nm) {
var self = this;
this.id = _id;
this.name = _nm;
this.print = function () {
$("#output").append("<p>New Person Id: "+this.id+"; Name: "+ this.name + "<p/>");
};
return this;
};
var nperson = new NewPerson(456, "Marcos");
nperson.print();
This will output:
New Person Id: 456; Name: Marcos
In essence, new is creating a new object represented by this, and you must return this to have a reference to the object created. In fact, if you do not use the new before creating an object, you end up referencing a global instance of this. Try the following:
var nperson = new NewPerson(456, "Marcos");
this.name = "Hello";
nperson.print();
var nperson1 = NewPerson(456, "Marcos");
this.name = "Hello";
nperson1.print();
You will see that the first output will be as expected:
New Person Id: 456; Name: Marcos
But the second will pick up the change made to this.name:
New Person Id: 456; Name: Hello
Here is the JSFiddle.
I am getting following error
Unable to get property 'showMsg' of undefined or null reference
on the last line of below code:
Function.prototype.showMsg = function () {
alert("This is a sample message.");
};
function Person() {
this.name = "Mahesh";
};
var personObj = new Person();
personObj.prototype.showMsg();
Actually I should be able to access showMsg() from Person instance since I have added it to the Function.prototype. Then why I am getting this error?
Well You Understand it all Wrong
Function.prototype.showMsg = function () {
alert("This is a sample message.");
};
function Person() {
this.name = "Mahesh";
};
var personObj = new Person();
personObj.prototype.showMsg();
First you prototyped the function class, then create a custom class called Person, then you create an instance of Person. And then you are calling the very blue print which is showMsg which is 2 Mistakes 1 showMsg is not Bounded into the Person and then to call it if its bounded you call it directly like this
personObj.showMsg()
Will To Make This Script Work from my point of View if i got you write
write it like this ->
function Person() {
this.name = "Mahesh";
};
Person.prototype.showMsg = function () {
alert("This is a sample message.");
};
var personObj = new Person();
personObj.showMsg();
my script bound the showMsg Directly to the Person Class if you need it through the Person Object and Through The Function Class To Then you have to inherit from Function Class Like This
Function.prototype.showMsg=function () {
alert("This is a sample message.");
};
function Person() {
this.name = "Mahesh";
};
Person.prototype = Function;
Person.prototype.constructor = Person;
var personObj = new Person();
personObj.showMsg();
Regards