I'm trying to define a non-enumerable toJSON function on a prototype object without much luck. I'm hoping for something similar to ECMAScript 5 toJSON:
Object.defineProperty(obj, prop, { enumerable: false });
However this defines it as a property which cannot be accessed as a method.
[EDIT: Nick is wrong; it can be accessed as a method. His mistake was in code that is not shown in this question - see his comments on answers below, for details.]
I was hoping to be able to define the function in a non-enumerable fashion, as I was planning to define in the prototypes of all primitive types (String, Number, Boolean, Array, and Object), so that I can recursively apply the function through complex objects.
The end goal here is to be able JSONify a Backbone model/collection with nested collections recursively.
I guess in total I have two main questions:
Is it possible to define a non-enumerable function on a prototype? If so how?
Is there a better way to JSONify nested Backbone models?
I don't get it, why can't you access it as a method?
var foo = {};
Object.defineProperty(foo, 'bar', {
enumerable: false,
value: function () {console.log('foo.bar\'d!');}
});
foo.bar(); // foo.bar'd!
If you wanted it on the prototype, it's as easy as
Object.defineProperty(foo.prototype, /* etc */);
or even directly in Object.create
foo.prototype = Object.create(null, {
'bar': {value: function () {/* ... */}}
});
However, unless you're creating instances of foo, it won't show up if you try to foo.bar, and only be visible as foo.prototype.bar.
If foo has it's own prototype (e.g. foo = Object.create({})), you can get it with Object.getPrototypeOf, add the property to that and then foo.bar would work even if it is not an instance.
var proto = Object.getPrototypeOf(foo); // get prototype
Object.defineProperty(proto, /* etc */);
You can see visibility of enumerable vs non-enumerable properties here.
Paul S. is right about needing to set the property definition's value instead of a get, but I wanted to add that you don't need to pass enumerable: false, because false is the default for that option in Object.defineProperty() The answer can be simplified to:
var foo = {};
Object.defineProperty(foo, 'bar', {
value: function(){ console.log('calling bar!'); }
});
foo.bar();
Always you can avoid enumerable functions properties in object when you looping through it. And instead of define property in each object and set enumerable to false , you can create function which will call to any object with the property you want and put a condition to not take the property in the looping list. here is the example :
const obj = {
name: "myName",
title: "developer"
}
function prop() {
this.loop = function(i) {
for (i in this) {
if (typeof(this[i]) == "function") {
continue;
} else {
console.log(this[i]);
}
}
}
}
prop.call(obj);
obj.loop();
output >> myName, developer
Related
I'm having an issue with providing a static getter function for the length property of my ES6 class extends.
As it turns out the actual Function.length getter always takes precedence over my own implementation.
class Foo {
static get value() {
return 'Foo';
}
static get length() {
return this.value.length;
}
}
class Bar extends Foo {
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
In the example above, Foo does exactly what I expected it to do, Bar not so much. Bar.value does indeed return 'FooBar', but Bar.length being 0 surprised me.
It took me a while to realize where the 0 came from, as I fully expected it to be 6 (and would have understood 3 to some degree).
As it turns out the 0 value provided by Bar.length is in fact the length of the constructor function of Bar, I realised this when wrote the same example in ES5 notation, there is a quick way to prove this though; simply add a constructor to Bar.
class Bar extends Foo {
constructor(a, b, c, d) {
// four configured parameters
}
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 4
There are ways around this:
add the static get length() to all extends (not my idea of
inheritance)
use a different property name (e.g. static get size() works as intended, but is not a generally used property in JS)
extend the base from a built-in class which has a working length (e.g. class Foo extends Array {...}) -
None of these are what I want to do if there's a more appropriate way to do this.
So my question is; does anyone know a proper way to have a custom property override which is inherited as expected, or am I being too stubborn?
As mentioned, I figured out what went wrong by writing the class syntax to (what I believe) would be the ES5 equivalent, as it may be beneficial to other developers and may shed some light on how I think ES6 classes work I'll leave it here.
(If anyone has a tip on how to make this bit collapsable on Stackoverflow, feel free to edit/suggest)
What I suppose is happening in ES5 syntax
I am aware ES6 classes are mostly syntactic sugar around the prototypal inheritance JS has, so what seems to happen for Bar is something like;
function Foo() {}
Object.defineProperties(Foo, {
value: {
configurable: true,
get: function() {
return 'Foo';
}
},
length: {
configurable: true,
get: function() {
return this.value.length;
}
}
});
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, {
value: {
configurable: true,
get: function() {
return 'Bar' + Foo.value;
}
}
});
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
I would've expected the property descriptors of Foo to be taken into account, like:
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, Object.assign(
// inherit any custom descriptors
Object.getOwnPropertyDescriptors(Foo),
{
configurable: true,
value: {
get: function() {
return 'Bar' + Foo.value;
}
}
}
));
console.log(Foo.value, Foo.length); // 'foo', 3
console.log(Bar.value, Bar.length); // 'bar', 6
About static members
Static members of an ES6 class are in fact members of the function object rather than its prototype object. Consider the following example, where I'll use regular methods instead of a getter, but the mechanics are identical to getters:
class Foo {
static staticMethod() {
return 'Foo static';
}
nonStaticMethod() {
return 'Foo non-static';
}
}
staticMethod will become a member of the constructor function object, whereas nonStaticMethod will become a member of that function object's prototype:
function Foo() {}
Foo.staticMethod = function() {
return 'Foo static';
}
Foo.prototype.nonStaticMethod = function() {
return 'Foo non-static';
}
If you want to run staticMethod from a Foo 'instance' you'll have to navigate to its constructor first, which is the function object where staticMethod is a member of:
let foo = new Foo();
foo.staticMethod(); // Uncaught TypeError: foo.staticMethod is not a function
// Get the static member either on the class directly
// (this works IF you know that Foo is foo's constructor)
Foo.staticMethod(); // > 'Foo static'
// this is the same, provided that neither 'prototype' nor
// 'prototype.constructor' has been overridden afterwards:
Foo.prototype.constructor.staticMethod(); // > 'Foo static'
// ...or by getting the prototype of foo
// (If you have to perform a computed lookup of an object's constructor)
// You'll want to perform such statements in a try catch though...
Object.getPrototypeOf(foo).constructor.staticMethod(); // > 'Foo static'
function.length
All functions have a length property that tells you how many arguments that function accepts:
function Foo(a, b) {}
Foo.length; // > 2
So in your example, a prototype lookup for Bar.length to Foo.length will indeed never occur, since length is already found directly on Bar. A simple override will not work:
Foo.length = 3;
Foo.length; // still 2
That is because the property is non-writable. Let's verify with getOwnPropertyDescriptor:
Object.getOwnPropertyDescriptor(Foo, 'length');
/*
{
value: 0,
writable: false,
enumerable: false,
configurable: true
}
*/
Also, instead of the value getter you define, you can instead just use function.name to get the name of a function / class constructor:
Foo.name; // > 'Foo'
Let's use this to override the length property on Foo. We are still able to override Foo.length because the property is configurable:
Object.defineProperty(Foo, 'length', {
get() {
return this.name.length;
}
});
Foo.length; // 3
This is code bloat
It is highly undesirable to have to do this for each extending class, or define a static getter for each, which is equivalent to the code above. It is not possible to entirely override the behaviour without any decoration of the function objects of some sort. But since we know that classes are just syntactic sugar, and we are actually just dealing with objects and functions, writing a decorator is easy!
function decorateClasses(...subjects) {
subjects.forEach(function(subject) {
Object.defineProperty(subject, 'value', {
get() {
const superValue = Object.getPrototypeOf(this).value || '';
return superValue + this.name;
},
enumerable: true,
configurable: true,
});
Object.defineProperty(subject, 'length', {
get() {
return this.value.length;
},
enumerable: true,
configurable: true,
});
})
}
This function accepts one or multiple objects, on which it will override the length property and set a value property. Both are accessors with a get method. get value explicitly performs prototype lookups, and then combines the results with the name of the function it belongs to. So, if we have 3 classes:
class Foo {
}
class Bar extends Foo {
}
class Baz extends Bar {
}
We can decorate all classes at once:
decorateClasses(Foo, Bar, Baz);
If we access value and length on all three classes (functions) we get the desired results:
Foo.value; // 'Foo'
Foo.length; // 3
Bar.value; // 'FooBar'
Bar.length; // 6
Baz.value; // 'FooBarBaz'
Baz.length; // 9
I have a DTO type that really is a map of key/value pairs. I would typically use an object literal for this for terseness, but this preculdes the resulting object having the [[prototype]].constructor set to a meaningful value.
e.g.
function MyDto() {
var o = {
myProperty: null
};
return o; //[[prototype]].constructor is meaningless
}
Is there a way to do something similar, but have the [[prototype]].constructor property set to the more meaningful MyDto (instead of Object)?
Not very much sure what you want to do. But this may help..
function MyDto() {
var o = {
myProperty: null
};
Object.setPrototypeOf(o,MyDto.prototype);
return o;
}
a = MyDto();
console.log(a);
To make obj instanceof Foo work, the prototype of obj has to point to the value of the prototype property of the function (Foo). A couple of ways have already been suggested, here is another one:
Call the function with new and return this (implicitly or explicitly). If you want to be able to call the function without new (not really clear from your question), check inside the function whether it was called with new or not:
function MyDto() {
if (!(this instanceof MyDto)) {
return new MyDto();
}
Object.assign(this, {myProperty: null});
}
Note: The constructor property has no meaning internally, only to the developers using your code.
I don't think I understand your question, but you might try this:
o.constructor = MyDto;
This will set o's constructor as MyDto, but will have no effect when doing o instanceof MyDto.
If this is what you want, my suggest is that you instantiate MyDto instead:
function MyDto() {
this.myProperty = null;
}
var o = new MyDto();
console.log(o instanceof MyDto); // true
console.log(o.constructor === MyDto); // true
EDIT: If you return within a function, then you will lost the reference to your new instance. In your case MyDto works as a factory to instances of Object that have an own property called myPropert.
EDIT 2: I still prefer the other way, but using Object.create also works:
function MyDto() {
return Object.create(MyDto.prototype, {
myProperty: {
writable: true,
configurable: true,
value: null
}
});
}
new MyDto() instanceof MyDto; // true
new MyDto().constructor === MyDto; // true
You're approaching this from the wrong direction. If you want the result of new Class() be a real instanceof Class, just extend the default instance object, instead of creating and returning a new one.
function Class () {
_.extend(this, {
property: 'value',
// ...
});
}
(The above code uses Lo-Dash function _.extend() to keep your code short & sweet. Similar implementations may be found in almost all utility libraries or bigger JavaScript frameworks).
In JavaScript (ES5+), I'm trying to achieve the following scenario:
An object (of which there will be many separate instances) each with a read-only property .size that can be read from the outside via direct property read, but cannot be set from the outside.
The .size property must be maintained/updated from some methods which are on the prototype (and should stay on the prototype).
My API is already defined by a specification so I can't modify that (I'm working on a polyfill for an already-defined ES6 object).
I'm mostly trying to prevent people from shooting themselves in the foot accidentally and don't really have to have bulletproof read-only-ness (though the more bullet-proof it is, the better), so I am willing to compromise some on side door access to the property as long as directly setting obj.size = 3; isn't allowed.
I'm aware that I could use a private variable declared in the constructor and set up a getter to read it, but I would have to move the methods that need to maintain that variable off the prototype and declare them inside the constructor also (so they have access to the closure containing the variable). For this particular circumstance, I'd rather not take my methods off the prototype so I'm searching for what the other options might be.
What other ideas might there be (even if there are some compromises to it)?
OK, so for a solution you need two parts:
a size property which is not assignable, i.e. with writable:true or no setter attributes
a way to change the value that size reflects, which is not .size = … and that is public so that the prototype methods can invoke it.
#plalx has already presented the obvious way with a second "semiprivate" _size property that is reflected by a getter for size. This is probably the easiest and most straightforward solution:
// declare
Object.defineProperty(MyObj.prototype, "size", {
get: function() { return this._size; }
});
// assign
instance._size = …;
Another way would be to make the size property non-writable, but configurable, so that you have to use "the long way" with Object.defineProperty (though imho even too short for a helper function) to set a value in it:
function MyObj() { // Constructor
// declare
Object.defineProperty(this, "size", {
writable: false, enumerable: true, configurable: true
});
}
// assign
Object.defineProperty(instance, "size", {value:…});
These two methods are definitely enough to prevent "shoot in the foot" size = … assignments. For a more sophisticated approach, we might build a public, instance-specific (closure) setter method that can only be invoked from prototype module-scope methods.
(function() { // module IEFE
// with privileged access to this helper function:
var settable = false;
function setSize(o, v) {
settable = true;
o.size = v;
settable = false;
}
function MyObj() { // Constructor
// declare
var size;
Object.defineProperty(this, "size", {
enumerable: true,
get: function() { return size; },
set: function(v) {
if (!settable) throw new Error("You're not allowed.");
size = v;
}
});
…
}
// assign
setSize(instance, …);
…
}());
This is indeed fail-safe as long as no closured access to settable is leaked. There is also a similar, popular, little shorter approach is to use an object's identity as an access token, along the lines of:
// module IEFE with privileged access to this token:
var token = {};
// in the declaration (similar to the setter above)
this._setSize = function(key, v) {
if (key !== token) throw new Error("You're not allowed.");
size = v;
};
// assign
instance._setSize(token, …);
However, this pattern is not secure as it is possible to steal the token by applying code with the assignment to a custom object with a malicious _setSize method.
Honestly, I find that there's too many sacrifices to be made in order to enforce true privacy in JS (unless you are defining a module) so I prefer to rely on naming conventions only such as this._myPrivateVariable.
This is a clear indicator to any developer that they shouldn't be accessing or modifying this member directly and it doesn't require to sacrifice the benefits of using prototypes.
If you need your size member to be accessed as a property you will have no other choice but to define a getter on the prototype.
function MyObj() {
this._size = 0;
}
MyObj.prototype = {
constructor: MyObj,
incrementSize: function () {
this._size++;
},
get size() { return this._size; }
};
var o = new MyObj();
o.size; //0
o.size = 10;
o.size; //0
o.incrementSize();
o.size; //1
Another approach I've seen is to use the module pattern in order to create a privates object map which will hold individual instances private variables. Upon instantiation, a read-only private key gets assigned on the instance and that key is then used to set or retrieve values from the privates object.
var MyObj = (function () {
var privates = {}, key = 0;
function initPrivateScopeFor(o) {
Object.defineProperty(o, '_privateKey', { value: key++ });
privates[o._privateKey] = {};
}
function MyObj() {
initPrivateScopeFor(this);
privates[this._privateKey].size = 0;
}
MyObj.prototype = {
constructor: MyObj,
incrementSize: function () { privates[this._privateKey].size++; },
get size() { return privates[this._privateKey].size; }
};
return MyObj;
})();
As you may have noticed, this pattern is interesting but the above implementation is flawed because private variables will never get garbage collected even if there's no reference left to the instance object holding the key.
However, with ES6 WeakMaps this problem goes away and it even simplifies the design because we can use the object instance as the key instead of a number like we did above. If the instance gets garbage collected the weakmap will not prevent the garbage collection of the value referenced by that object.
I've been doing this lately:
// File-scope tag to keep the setters private.
class PrivateTag {}
const prv = new PrivateTag();
// Convenience helper to set the size field of a Foo instance.
function setSize(foo, size)
{
Object.getOwnPropertyDiscriptor(foo, 'size').set(size, prv);
}
export default class Foo
{
constructor()
{
let m_size = 0;
Object.defineProperty(
this, 'size',
{
enumerable: true,
get: () => { return m_size; },
set: (newSize, tag = undefined) =>
{
// Ignore non-private calls to the setter.
if (tag instanceof PrivateTag)
{
m_size = newSize;
}
}
});
}
someFunc()
{
// Do some work that changes the size to 1234...
setSize(this, 1234);
}
}
I think that covers all of the OP's points. I haven't done any performance profiling. For my use cases, correctness is more important.
Thoughts?
I came across this little snippet of code for property reflection in JavaScript:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
if (typeof obj[prop] !== "function") {
result.push(prop);
}
}
return result;
}
I've tested it using the following "CustomObject":
var CustomObject = (function () {
function CustomObject() {
this.message = "Hello World";
this.id = 1234;
}
Object.defineProperty(CustomObject.prototype, "Foo", {
get: function () {
return "foo";
},
enumerable: true,
configurable: true
});
Object.defineProperty(CustomObject.prototype, "Bar", {
get: function () {
return "bar";
},
enumerable: true,
configurable: true
});
return CustomObject;
})();
Here is a little test using jQuery:
$(document).ready(function () {
console.log(GetProperties(new CustomObject()));
});
Here are the results:
["message", "id", "Foo", "Bar"]
I understand that the GetProperties function just returns an array of anything in the input object that is not a function, but I want to filter the results to get only the "real" properties, so my output should be:
["Foo", "Bar"]
Is this possible?
Also, can I do the opposite and just return the fields?
There are two things you could do (and possibly more, it depends on your exact situation):
Name "private" properties differently, e.g. with a trailing underscore and check whether the property name ends with an underscore when you are iterating over the properties (and exclude them).
If by "real properties" you mean the properties defined on the prototype and you want to ignore all properties defined on the object itself, you can use .hasOwnPrototype to check where it is defined. Alternatively, you could use Object.getPrototypeOf and iterate over the properties of the prototype only.
Bad code. I'm leaving (with a comment) it 'cause the subsequent discussion
might help somebody else.
If you always use defineProperty() to get non enumerable properties, then this would work:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
// propertyIsEnumerable() returns false just because the properties
// are inherited thru the prototype chain. It was just a coincidence
// that it got the desired result. Don't do this.
if (typeof obj[prop] !== "function" && !obj.propertyIsEnumerable(prop)) {
result.push(prop);
}
}
return result;
}
Otherwise, I'd be curious to know a general solution to the problem.
EDIT: I see that the code has enumerable: true and still my code does exactly what was asked. Double you tee ef?
Object.create is a great addition to JavaScript, because it adheres more to the prototypical nature of JS. However, I can't help but find the syntax of the 2nd parameter to the function to be too verbose, and a step back.
For example, if I want to create an object, and specify a new property in the derived object, I need to include that property value within a property object, regardless if I'm interested in the extra features or not.
So, something as simple as this:
o = Object.create({}, { p: 42 })
Now becomes:
o = Object.create({}, { p: { value: 42 } })
Obviously this is a simple example, but to me the verbosity is unnecessary, and should be optional.
Does anyone understand the decision to require a properties object? What is your opinion of the requirement of the new syntax?
Note: I understand there are easy solutions to overcome this requirement.
The syntax is done this way so that you can add parameters that control each property:
So, when you do this:
o = Object.create({}, { p: { value: 42 } })
you are saying that you want a property named p with a value of 42. The key here is that there are other parameters you can set for each property and if there wasn't this extra level of object hierarchy, you wouldn't have any way to pass those extra parameters.
So, for example, you could also do this:
o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });
Here's you are not just specifying the value of 42, but also some options for that property. If there wasn't the extra level of object hierarchy here, then you wouldn't have a place to put those extra options.
Yes, it does seem inconvenient when you only want the simple case. But, you could easily write yourself a helper function that made the simpler syntax work:
function myCreate(proto, props, enumerable, writable, configurable) {
// last three arguments are optional - default them to true if not present
if (typeof enumerable === "undefined") {enumerable = true;}
if (typeof writable === "undefined") {writable = true;}
if (typeof configurable === "undefined") {configurable = true;}
var wrapper = {};
for (var i in props) {
wrapper[i] = {
value: props[i],
enumerable: enumerable,
configurable: configurable,
writable: writable
};
}
return(Object.create(proto, wrapper));
}
Demo here: http://jsfiddle.net/jfriend00/vVjRA/