Is it possible to get the non-enumerable inherited property names of an object?
Since getOwnPropertyNames
can get you non-enumerable properties, you can use that and combine it with walking up the prototype chain.
function getAllProperties(obj){
var allProps = []
, curr = obj
do{
var props = Object.getOwnPropertyNames(curr)
props.forEach(function(prop){
if (allProps.indexOf(prop) === -1)
allProps.push(prop)
})
}while(curr = Object.getPrototypeOf(curr))
return allProps
}
I tested that on Safari 5.1 and got
> getAllProperties([1,2,3])
["0", "1", "2", "length", "constructor", "push", "slice", "indexOf", "sort", "splice", "concat", "pop", "unshift", "shift", "join", "toString", "forEach", "reduceRight", "toLocaleString", "some", "map", "lastIndexOf", "reduce", "filter", "reverse", "every", "hasOwnProperty", "isPrototypeOf", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "propertyIsEnumerable", "__lookupSetter__"]
Update: Refactored the code a bit (added spaces, and curly braces, and improved the function name):
function getAllPropertyNames( obj ) {
var props = [];
do {
Object.getOwnPropertyNames( obj ).forEach(function ( prop ) {
if ( props.indexOf( prop ) === -1 ) {
props.push( prop );
}
});
} while ( obj = Object.getPrototypeOf( obj ) );
return props;
}
Accessing a object's non enumerable properties
You can write a function, let's call it getAllPropertyNames()
, that iterates through the prototype chain of the object and accumulates the properties of each level:
function getAllPropertyNames (o) { let propertyNames = []
for (let proto = o; proto !== null; proto = Object.getPrototypeOf(proto)) { propertyNames = propertyNames.concat(Object.getOwnPropertyNames(proto)) }
return propertyNames}
console.log(getAllPropertyNames({ mykey: 'value' }))
After Object.create: properties are there, but Object.keys / getOwnPropertyNames = []?
Object.create has two arguments. The first one is the prototype of the created object, and a second optional parameter is an object of property descriptors.
Object.create(proto[, propertiesObject])
If you create the object passing the properties object as the first argument,
let obj = Object.create({x: 1, y: 2});
this one will become the prototype of your new object.
As Object.keys() returns an array of only its own enumerable properties, the ones you passed when constructing it won't be listed.
To create the object the way you intended, yo can use Object.assign:
let obj = Object.assign({}, {x: 1, y: 2});
Why non-enumerable properties don't affect the array built-in methods?
It's because of the way the array iterator is specified. While it's most common to have dense arrays where every key is defined, sparse arrays are also supported, where only a handful of keys are defined. To support this, array iteration needs to be able to iterate past keys that don't actually exist. For example:
const arr = [];arr[0] = 0;arr[10] = 10;
console.log('has 0?', arr.hasOwnProperty(0))console.log('has 1?', arr.hasOwnProperty(1))
for (let val of arr) { console.log(val);}
Is it possible to emulate non-enumerable properties?
You can do it via code-rewriting. Rewrite every use of for (p in o) body
to
for (p in o) {
if (!(/^__notenum_/.test(p) || o['__notenum_' + p])) {
body
}
}
and then you can mark properties not enumerable by defining a __notenum_...
property. To be compatible you would have to tweak the above to make sure that __notenum_propname
is defined at the same prototype level as propname
, and if you use them, overwrite eval
and new Function
to rewrite.
That's basically what ES5/3 does.
Iterate over all properties, not just enumerable ones
- When does the loop
while (obj)
break?
When there are no more prototypes in the prototype chain getPrototypeOf
returns null
. For regular objects, this happens when you try to get the prototype of Object.prototype
.
- How do lines within the
while
block work to add the own property names ofobj
toresult
?
Array.prototype.push.apply(result, array)
passes each element in the array
as argument to result.push
. It is like calling result.push(a[0], a[1], ...)
where a
is Object.getOwnPropertyNames(obj)
.
Iterating through inherited object properties when hasOwnProperty() is false
for...in
only iterates over enumerable properties. All the properties on Object.prototype
are not enumerable, so they won't actually be iterated over.
Here is an example that would show inherited properties. We create a new object that inherits from another object, not from Object.prototype
:
var foo = {abc: 123};// Creates an object with property `fog: 'stack'` but has `foo` as its prototypevar buz = Object.create(foo, {fog: {value: 'stack', enumerable: true}});
for (var name in buz) { if (Object.prototype.hasOwnProperty.call(buz, name)) { console.log('this is fog (' + name + ') for sure. Value: ' + buz[name]); } else { console.log(name); // toString or something else }}
Related Topics
Sort Array by Firstname (Alphabetically) in JavaScript
How to Listen to a "Style Change" Event
Create Object from Class Name in Javasscript Ecmascript 6
Is There a Better Way to Do Optional Function Parameters in JavaScript
What Does "Options = Options || {}" Mean in JavaScript
How to Deal with Big Numbers in JavaScript
Difference Between Dates in JavaScript
After Calling Chrome.Tabs.Query, the Results Are Not Available
How to Get a Dom Element from a Jquery Selector
How to Fix Error: Listen Eaddrinuse While Using Nodejs
How to Prevent Enter Keypress to Submit a Web Form
Issue in Returning Data Retrieved from Db Queries Called in the Loop
Promise.All Consumes All My Ram
Constructors in JavaScript Objects
How to Concatenate a String with a Variable