cannot understand the Javascript setter and getter lookup in classes - javascript

I understand that JavaScript classes are syntactic sugar over prototypes and not works as pure classes in other OOP languages. But the problem here arises is on the getter and setter. When completely leaving getter and setter in the child class, it behaves normally but if I define any one of getter or setter broke these.
For example:
class A {
constructor() {
this.__value = "Default";
}
set value(value) {
console.log("setter called")
this.__value = value;
}
get value() {
console.log("getter called")
return this.__value;
}
}
class B extends A {
}
let b = new B();
b.value = 2;
console.log(b.value);
The above code works fine but if I define getter or setter in the child class the lookup won't go to parent class. I googled about it and found that, it is intentional and is ES standard. Then why when the child class has no methods the lookup reaches the parent class and able to access the getter and setter?

When you access an object property, either to set a value obj.prop = 'val' or to retrieve a value console.log(obj.prop), the engine will try to find that property in the object's prototype chain.
It starts at the instance. In this case, the instance doesn't have any properties, so it continues.
The next object is the instance's internal prototype, which is B.prototype. If B has the property name being looked at, it'll stop there. If there's a setter, and a value was assigned to the property, the setter will be invoked. If there's a getter, and the value being retrieved, the getter will be invoked.
That's it - once a property is found in the prototype chain, it'll stop searching.
If B.prototype didn't have the setter/getter, then the engine would proceed to the next object. The internal prototype of B.prototype is A.prototype. Then, A's setter or getter would be invoked.
It's possible to invoke the superclass's setters/getters from the child, but it looks a bit strange:
class A {
constructor() {
this.__value = "Default";
}
set value(value) {
console.log("setter called")
this.__value = value;
}
get value() {
console.log("getter called")
return this.__value;
}
}
class B extends A {
set value(value) {
console.log('sub setter calling super');
super.value = value;
}
get value() {
console.log('sub getter calling super');
return super.value;
}
}
let b = new B();
b.value = 2;
console.log(b.value);

After googling and lot of code execution I found an answer to my own question,If we define no accessors(getter or setter) in our child class the lookup will proceed towards the parent but if we set any accessor using the get or set descriptor in child class that will invoke the Object.defineProperty method and set the descriptor we mentioned.If we have both setter and getter there is no problem,but if we leave any one that leads to missing of those property in our current object.That's the reason why we get undefined as the undefined property gets undefined value.So literally we have found the value which is undefined thats the main reason we cannot proceed to the parent prototype as value(undefined) found in the current object and the lookup will stop.

Related

why my getter property is directly in my class instance?

I was testing a getter in my class and I faced a contrast in my implementation and document, based on MDN document a class getter property should be defined inside the instance's prototype
Getter properties are defined on the prototype property of the class and are thus shared by all instances of the class.
so why I can see the getter directly on my instance,
the issue I have with this implementation is, if we assume the getter property is only inside the instance's prototype so why the this is referred to the k not the Kevin.prototype because this in a getter function inherites the object which is located in it based on the MDN document
A function used as getter or setter has its this bound to the object from which the property is being set or gotten.
so in a nutshell, why we have getc directly in our class instance and why the getc value inside the prototype of k is lambo not undefined?
code:
class Kevin {
constructor(x) {
this.age = x;
this.car = "lambo"
}
get getc() {
return this.car;
}
}
const k = new Kevin(3);

ES6 Static Properties Subtle (Mis)Behavior in Inheritance

When one defines a static property on an ES6 class, and you have other classes that extend that class, any change to the property on the parent class will seem to change the value on all subclasses. This seems to be a subtle prototype chain issue. If you first set the property value on the subclass then it seems to "own" it--i.e. it won't reflect changes to the super class. My issue is that I want a class property that flags a guaranteed one-time-only initialization the first time a class is used, and because this is a library/framework I don't want to have to force users to explicitly set the static value in their own subclass definitions. Other than having a global that tracks it instead, is there any other way to keep static properties separate across subclasses?
Code that demonstrates problem:
class Class1 {
static get initialized() { return this.$initialized }
static set initialized(flag) { this.$initialized = flag}
}
class Class2 extends Class1 {}
Class1.initialized -> undefined
Class1.initialized = false;
Class2.initialized -> false
Class1.initialized = true;
Class2.initialized -> true
The problem is that the $initialized property is inherited as well, so once the superclass is initialised then this will be reflected in all subclasses. You can write your getter so that it ignores inherited properties though:
class Class1 {
static get initialized() {
return this.hasOwnProperty("$initialized")
? this.$initialized
: undefined; // or whatever default value you want
}
static set initialized(flag) {
this.$initialized = flag
}
}

Why does overriding set method only (or getmethod only) from a parent class in Javascript return undefined for it's counter part?[ES6] [duplicate]

class AbstractClass {
constructor() {
}
set property(value) {
this.property_ = value;
}
get property() {
return this.property_;
}
}
class Subclass extends AbstractClass {
constructor() {
super();
}
set property(value) {
super.property = value;
if (!(this.property_ instanceof SubclassAssociatedClass)) throw new TypeError();
}
//get property() {
// return super.property;
//}
}
Override the set method of an attribute and it appears the get method must be overridden also, otherwise undefined is returned (i.e., the get method is not inherited, uncomment the subclass get property() method above and everything works fine).
I assume this is a part of the spec., it would follow though possibly if the behaviour was a consequence of cross compiling. Just to be sure, is this the correct way to code overridden setters and getters (both at the same time or not at all)?
Yes, this is intentional (a part of the spec). If an object has an own property (.property in your example), this property will be used and not an inherited one. If that property is existent, but is an accessor property without a getter, then undefined will be returned.
Notice that this behaviour has not changed from ES5.

Why does my javascript getter/setter require underscores?

Performing a [[Get]] or [[Put]] operation on a throws a RangeError that states Maximum call stack size exceeded pointing to the this.a in the getter and the = in the setter.
let someObject = {
get a() {
return this.a;
},
set a(val) {
this.a = val;
}
}
someObject.a; // Error
someObject.a = 5; // Error
If the properties inside the getter and setter are underscored they work however:
let someObject = {
get a() {
return this._a_;
},
set a(val) {
this._a_ = val;
}
}
I've tested this in both the node environment and the v10 engine in Chrome and the same thing happens.
Such confusion. Send help.
Because by doing return this.a you're accesing the a property, which triggers the getter function, which accesses the a property, which triggers the getter function, which accesses the a property, which triggers the getter function... Endless loop.
Same for setter.
You need to have a variable that has a different name then the getter/setter. The most common way is to prefix the variable with an _.
Otherwise if you don't do this you will have an endless loop of calls to the getter/setter.
class A {
constructor() {
this._a = '';
}
get a() {
// If we don't call it like this
// We will be calling the getter again
// Which in return will call itself again
return this._a
}
}
Once an object has been defined with a setter for some property, that setter is always used to set the property value — even inside the setter itself! If you attempt to set the property with simple assignment inside the setter, JavaScript will call the setter again, and you get infinite recursion.
Using a leading special character like "_" for a second "secret name" is a common convention. However, that property is still externally visible (though it can be made non-enumerable). Another approach available in newer JavaScript environments is to use a Symbol instance instead of a property name. Symbol instances guarantee that your internal property identifier cannot ever collide with another property name from some other source in the application.
So:
let someObject = function() {
var aKey = Symbol();
return {
get a() {
return this[aKey];
},
set a(value) {
this[aKey] = value;
}
};
}();
That code uses a closure to create a private variable for the actual property key for what externally looks like a property called "a". It won't be possible for any other code to accidentally "step on" the private actual property used by the setter/getter pair because that's what Symbol is for.

hasOwnProperty returns true, when checked against parent object properties

My JavaScript code:
console.clear();
function BaseClass(nname) {
var name = nname;
this.bc_PublicProperty = "DefaultValue_BaseClass";
this.bc_getName = function GetName() {
return name;
};
this.bc_setName = function SetName(nname) {
name = nname;
};
}
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_PublicProperty = "DefaultValue_SubClass";
this.sc_getName = function GetName() {
return name;
};
this.sc_setName = function SetName(nname) {
name = nname;
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
console.log("hasOwnProperty check on subclass object 'sc' returns true for Method 'bc_getName'");
for (var pro in sc) {
console.log("Is " + pro + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, pro));
}
I have two objects (BaseClass and SubClass). One inherits from the other using the constructor pattern, as explained on MDN.
Now, when I iterate over all properties of the subclass object, they all return true for hasOwnProperty, even for the parent methods/properties, except constructor.
Does it mean, that it breaks when using the constructor pattern?
When I put public properties and methods in the constructor function, whether in BaseClass or SubClass, they will always be "marked" as own properties/methods. When I instead attach them to the respective prototype, the hasOwnProperty will output "false" for them.
Whether you put the public methods/properties to the prototype or to the constructor function itself, they will all be available for use in the subClass (--> SubClass2, --> SubClass3).
The only thing, that I can think of right now, why you should attach them to the prototype object, is because of efficiency reasons, as explained here, "Defining class methods"-section. In order not to add closures for every constructed instance.
Value Types should be declared on the prototype, but not for instance variables whose initial values are dependent on arguments to the constructor, or some other state at time of construction.
You can override both properties/functions irrespective of their place of declaration.
Also setting up getters and setters on the prototype, for instance to set or get a private variable, makes no sense, as the private variable has to be public, in order to be accessible by the getters and setters attached to the prototype.
Therefore it makes no sense to use getters and setters. You can access the public variable directly.
I have to adjust my question a bit now:
When do I need hasOwnProperty, if actually public props/functions should be declared on the prototype, which in turn will all output Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case, when it makes sense, to use hasOwnProperty.
console.clear();
var l = function(v) {
console.log(v);
};
function BaseClass(nname) {
this.bc_nameProp = nname;
this.bc_ownFunc = function() {
l("bc_ownFunc of BaseClass called");
};
this.bc_getName = function GetName() {
return this.bc_nameProp;
};
}
BaseClass.prototype.bc_getName = function GetName() {
return this.bc_nameProp;
};
BaseClass.prototype.bc_PublicProperty = "DefaultValue_BaseClass";
BaseClass.prototype.bc_setName = function SetName(nname) {
bc_nameProp = nname;
};
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_setName = function SetName(nname) {
bc_nameProp = nname;
};
this.bc_getName = function GetName() {
return "xyz";
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sc_getName = function GetName() {
return this.bc_nameProp;
};
SubClass.prototype.sc_PublicProperty = "DefaultValue_SubClass";
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
l("----- iterating over BaseClass properties ------");
l("");
for (var pro in bc) {
l("Is " + pro + " own property of BaseClass: --> " + Object.hasOwnProperty.call(bc, pro));
}
l("");
l("----- iterating over SubClass properties ------");
l("");
for (var p in sc) {
l("Is " + p + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, p));
}
l(bc.bc_getName());
l(sc.bc_getName());
l(sc.sc_getName());
Solution
When I asked this question, I was of the opinion, that when using classical inheritance in JavaScript, I can differentiate which properties/functions of my subclass directly belong to it, using hasOwnProperty. Which is not possible, as all the properties/functions of the parent prototype are copied to the prototype of the SubClass:
SubClass.prototype = Object.create(BaseClass.prototype);
All properties/functions attached to prototypes return "false", when using hasOwnProperty.
And if you have public properties/functions declared in the constructor functions of BaseClass and SubClass, all these properties return "true", when calling hasOwnProperty for these properties on the subclass.
These are copied to the SubClass using this statement:
BaseClass.call(this, nname);
So using hasOwnProperty while iterating over all properties of an obj of type SubClass, will output false for all properties/functions declared on prototype level and true for all properties/functions declared on constructor function level.
Now, I understand why using hasOwnProperty in this use case makes no sense.
Check that you're calling BaseClass.call(this) on SubClass's constructor, meaning that you're adding BaseClass properties and functions to the SubClass instance, because this is an instance of SubClass.
This is why hasOwnProperty returns true for all properties.
Wrong prototypes...
At the end of the day, you're not taking advantage of prototypes in JavaScript.
Functions that must be part of any instance of some prototype should be defined in the prototype itself.
var A = function() {};
A.prototype = {
doStuff: function() {}
};
Actually, the only benefit of defining functions during construction-time is that you ensure that an object will always define some functions/properties, but you're ensuring this once the object has been already created.
For me, there's a very small difference between the following ways of defining properties:
var A = function() {};
var instance = new A();
instance.text = "Hello, World!";
// or...
var A = function() {
this.text = "Hello, World!";
};
var instance = new A();
The first code sample defines a text property after the constructor has been called while the second one does it inside the constructor, but in both cases either this or instance are references to the same object (i.e. the instance of A).
With prototypes you ensure that all objects created from some constructor function will share the same members, and these members will be inherited and consumed using prototype chain.
About the OP's update...
The OP said a lot of things, but summarizing said:
[...] I have to adjust my question a bit now: When do I need
hasOwnProperty, if actually public props/functions should be declared
on the prototype, which in turn will all output
Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case,
when it makes sense, to use hasOwnProperty.
You're going in the wrong way... Why asking yourself when you need hasOwnProperty? Ask yourself when you need simple objects with less reusability or when you need actual reusability. hasOwnProperty has nothing to do with this issue.
When you use a literal object (i.e. ones declared as is with {} syntax)? When you need dictionaries, argument maps, value objects... Here you like hasOwnProperty because usually your code receiving arguments will look like this:
function X(uri, options) {
if(typeof options != "undefined") {
// For example, we set a default value if options has no
// mimeType property...
options.mimeType = options.hasOwnProperty("mimeType") ? options.mimeType : "application/json";
}
}
When do you use complex objects using prototypes? When you define behavior and you need to reuse it across your application or even multiple applications, and also you need to add more behavior on top of generic requirements (hello inheritance).
About why using hasOwnProperty...
The OP said:
But why would you use "hasOwnProperty" here, if you want to check the
existence of an property? Shouldn't it be: options.mimeType =
options.mimeType || "application/json";
There's a lot of code on the Internet doing the `options.mimeType =
options.mimeType || "application/json", right, because in JavaScript undefinedevaluates tofalse(ifoptionsdoesn't own amimeTypeproperty returnsundefined`).
In my humble opinion, I would use hasOwnProperty because it returns a boolean either if it exists or it exists and it has undefined as the value.
For example, options could be defined as { mimeType: undefined } and sometimes you want to know if the property exists even if it has undefined as value. The undefined as false treats the case of if it's undefined, either if it exists or not, do X, and hasOwnProperty is I want to be sure it has the property or not.
So why would I use options.hasOwnProperty over other approaches?. Easy: because, since language gives a tool to verify if a property exists in some object, why do I need a trick? object.hasOwnProperty returns true or false, and I'm sure the property exists or not, even if the property has undefined value.
With options.hasOwnProperty("mimeType") I can throw an Error if it exists and it has an undefined value. Why do I prefer this? Because I like the fail-fast concept: if you gave me the property with undefined value I tend to think that there's some bug in your code. Define it or not, my friend!
I'm going to assume by "constructor" pattern, you mean assigning this.fn = function (){}; and this.val = true; in the constructor function.
The this in the context of the BaseClass.call is changed to be the sub class, so all assignments within that are made on the sub class itself. Strictly speaking this isn't actually doing any sort of inheritance at all. Let me explain a bit in the code.
SubClass.prototype = Object.create(BaseClass.prototype);
In this line, you would be inheriting the prototype of the BaseClass on the sub class, which would ordinarily mean inheritance. However, the prototype for the BaseClass is the exact same prototype of the Function object, which the SubClass was already inheriting from. The this.___ assignments do not add to the prototype of an object, only to an instance of that object. To add to the prototype, you would need to do something along the lines of BaseClass.prototype.___ = 'foo'; However, you don't want to do that in the constructor, as that assignment is then happening every time you create a new object.
Also, in your code, calling SubClass.getName will throw an error. name is not defined in that context, only in the BaseClass context.

Categories