'What happens when invoke Object.defineProperty for a function's prototype?
var Foo = function(){};
Object.defineProperty(Foo.prototype,'x',{
get(){
return 3;
}
});
var foo = new Foo();
console.dir(foo);
The result I am looking for should be
Foo {
__proto__:{
constructor: ƒ (),
x: 3,
__proto__: Object
}
}
But the real result is
Foo {
x: 3,
__proto__:{
constructor: ƒ (),
x: 3,
__proto__: Object
}
}
Why is the x attribute already appearing at the outermost layer?
Solution 1:[1]
What Happened (Step-by-step)
var Foo = function(){};
A new function is defined, named - Foo. If we use console.dir(Foo) we will see that Foo has 2 special members prototype and __proto__
Object.defineProperty(Foo.prototype,'x',{
get(){
return 3;
}
});
The prototype of Foo is updated. About defineProperty (From MDN):
The static method Object.defineProperty() defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
So the prototype object is now modified with a new member named x. The prototype here acts as a c'tor and will "kick-off" when a new instance of Foo will be created
var foo = new Foo();
A new instance of Foo is created. the c'tor call is using Foo prototype and x getter is applied
Alternatives
Extending Foo prototype, thus making sure it will effect only objects created from Foo (as a class)
Object.defineProperty(Foo.prototype, 'x',
{
get: () => 3
});
console.dir(new Foo().x) // will show 3
console.dir(Foo.x) // undefined - protorype is for class objects
Or extending Foo __proto__, thus updating Foo as a function and while not affecting objectes created from it
Object.defineProperty(Foo.__proto__, 'x',
{
get: () => 3
});
console.dir(new Foo().x) // undefined - x is not a member of Foo
console.dir(Foo.x) // 3
Bonus: a very good article about JS prototypes and why this is happening
Original Answer
This is happening because in JS function is a way to declare BOTH functions and classes!
So your Foo function can be also used as a class
var Foo = function(){};
Foo(); // call Foo as a function
var obj = new Foo(); // initiate an instance from class Foo
Because you are using Foo.prototype object (as a function) and then you create a new instance from your Foo class you guarantee that:
- Your function prototype will be modified with your new getter
- Every new object (that inherits) from your class will also use your new getter (in object level)
I really think that your code should be something like this instead:
function Foo ()
{
Object.defineProperty(this,'x',{
get(){
return 3;
}
});
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Glorfindel |
