I was wondering if it was possible to iterate through methods and properties of the Object function (or similar built-in functions)
I can iterate through the document and window object via for(var key in window) console.log(key)
However, the 'Object' being a function does not work that way. As I saw at MDN there are plenty of methods for it, for instance - Object.isExtensible() However, for(var key in Object) console.log(key) will only return undefined
Thanks for the help.
Use Object.getOwnPropertyNames:
// functions directly within Object
Object.getOwnPropertyNames(Object).forEach(function(name) {
// do whatever you want with the name here
}
// methods of Object instances
Object.getOwnPropertyNames(Object.prototype).forEach(function(name) {
// do whatever you want with the name here
}
Related
I'm trying to create a simulator for console.log to use it in my phone to show deferant datatype result, code errors - the code is working fine and display, highlight all datatypes
but i want also to display constcrutor, scopes, prototypes like the web console is there's a way to loop throw them and get their data like this image
The constructor property can be gotten by referencing it explicitly, or by iterating over all properties of the object (not just enumerable properties), with Object.getOwnPropertyNames.
The [[Prototype]] property is equivalent to the value returned by Object.getPrototypeOf, so you can call that to access the prototype object and iterate through it too, if you want.
Perhaps something like:
const recursiveLogAllProperties = (obj) => {
Object.getOwnPropertyNames(obj).forEach(prop => console.log(prop, obj[prop]));
const proto = Object.getPrototypeOf(obj);
if (proto === Object.prototype) return;
console.log('------ Prototype:');
recursiveLogAllProperties(proto);
}
const arr = [1, 2];
recursiveLogAllProperties(arr);
The [[Scopes]] internal property is not accessible from JavaScript.
I am using Map
because I want to store an object as a key.
My question is - can I access a map the same way I would access a plain object?
For example:
let m = new Map();
let obj = {foo:'bar'};
m[obj] = 'baz';
console.log(m[obj]);
is this supposed to work correctly as is, or do I need to use the get/set methods of a Map?
The reason I ask is because if I need to use get/set it forces to me to carefully refactor a lot of code.
Here is a real life example of code that may need to be refactored:
// before (broker.wsLock was plain object)
function addWsLockKey(broker, ws, key) {
let v;
if (!( v = broker.wsLock[ws])) {
v = broker.wsLock[ws] = [];
}
if (v.indexOf(key) < 0) {
v.push(key);
}
}
// after (broker.wsLock is a Map instance)
function addWsLockKey(broker, ws, key) {
let v;
if (!( v = broker.wsLock.get(ws))) {
v = [];
broker.wsLock.set(ws, v);
}
if (v.indexOf(key) < 0) {
v.push(key);
}
}
is there some way to set v on the same line as the set() call?
If you want access to the actual values of the Map object, then you have to use .get() and .set() or various iterators.
var m = new Map();
m.set("test", "foo");
console.log(m.get("test")); // "foo"
Regular property access on a Map such as:
m["test"] = "foo"
just sets a regular property on the object - it does not affect the actual map data structure.
I imagine it was done this way so that you can access the Map object properties separately from the members of the Map data structure and the two shall not be confused with one another.
In addition, regular properties will only accept a string as the property name so you can't use a regular property to index an object. But, map objects have that capability when using .set() and .get().
You asked for a "definitive" answer to this. In the ES6 specification, you can look at what .set() does and see that it operates on the [[MapData]] internal slot which is certainly different than the properties of an object. And, likewise, there is no where in that spec where it says that using normal property access would access the internal object [[MapData]]. So, you'll have to just see that normal property access is describe for an Object. A Map is an Object and there's nothing in the Map specification that says that normal property access should act any different than it does for any other object. In fact, it has to act the same for all the methods on the Map object or they wouldn't work if you happened to put an item in the Map with the same key as a method name. So, you're proof consists of this:
A simple test will show you that property access does not put anything in the Map itself, only a regular property.
The spec describes a Map as an object.
The spec describes how .get() and .set() operate on the internal slot [[MapData]].
There's nothing in the spec that says property access on a Map object should work any different than it always does.
If property access did access the MapData, then you would not be able to access methods if you happened to put a key in the Map that conflicted with a method name - that would be a mess if that was the case.
Running this JavaScript lists in Firefox 60.2 only one property ("location"), but there are many others, like "document.title" etc.
window.console.log("List props: " + Object.keys(window.document).sort().join(' / '));
Why is it this way? Safety? How is this done technically?
How can I list all properties?
Object.keys(o) returns the own, enumerable properties of o.
Own: properties defined directly on o, not on its prototype chain:
Enumerable: a flag that controls if a given property is included when listing an object's properties.
In this case most of the keys you expect are defined on another object in in document's prototype chain:
document.hasOwnProperty("title"); // false
document.__proto__.__proto__.hasOwnProperty("title"); // true
document.__proto__.__proto__.propertyIsEnumerable("title"); // true
You can use a for... in loop to find the enumerable properties that are defined on an object or its prototype chain:
for (let key in window.document) {
console.log(key);
}
The reason is that Object.keys() returns returns an array of strings that represent all the enumerable properties of the given object.
Try this to see which properties of document are enumerable
for(let key in document){
let isEnumerable = document.propertyIsEnumerable(key);
console.log(`docment['${key}'] isEnumerable?:${isEnumerable}`);
}
However as the previous answer has stated you can use a for-in loop to get all properties in an array sort them and join them
I couldn't find an official reason for it not working with window.document but it seems you can reproduce this behavior with other variables as well.
The issue seems to be Object.keys() not returning everything from these variables.
If you're still trying to get all properties of document, you can still use
var props = [];
for(var prop in window.document) {
props.push(prop);
}
console.log("List props: " + props.sort().join('/'));
Which will do the exact same thing as your approach.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I check if an object has a specific property in JavaScript?
I found the following snippet in Twitter's JavaScript files. Why do they need to call the hasOwnProperty function to see dict has the key property? The for loop is running for each 'key' in 'dict' which means 'dict' has 'key'. Am I missing a point?
function forEach(dict, f) {
for (key in dict) {
if (dict.hasOwnProperty(key))
f(key, dict[key]);
}
}
Because if you don't, it will loop through every property on the prototype chain, including ones that you don't know about (that were possibly added by somebody messing with native object prototypes).
This way you're guaranteed only the keys that are on that object instance itself.
The hasOwnProperty method lets you know if a property is directly on an instance of an object or inherited from its prototype chain.
Consider the following
function ObjWithProto() {
this.foo = 'foo_val';
}
ObjWithProto.prototype = {bar: 'bar_val'};
var dict = new ObjWithProto();
dict.foobar = 'foobar_val';
I.e., you have an Object dict with properties foo and foobar that also inherits a property bar from its prototype chain.
Now run it through (a modified version of) your code:
function forEach(dict) {
var key;
for (key in dict) {
if (dict.hasOwnProperty(key))
console.log('has', key, dict[key]);
else
console.log('not', key, dict[key]);
}
}
forEach(dict);
You will see
has foo foo_val
has foobar foobar_val
not bar bar_val
This lets you separate properties that an object has itself and those it has inherited (which are usually methods that aren't relevant to the loop).
Furthermore, if you now do dict.bar = 'new_bar_val';, the last result will change to has bar new_bar_val, letting you distinguish even between properties of the same name as those inherited.
Every object in JavaScript is a dictionary. This means that "toString" and every other method is a key of every Object:
var myObj = {};
console.log(myObj["toString"]);
But this function is inherited from Object class, so hasOwnProperty tells you if this key is owned by the dictionary or if it is inherited.
"toString" in myObj; // true
myObj.hasOwnProperty("toString") // false
blockhead is right here. For example, the Prototype.js framework used to extend native arrays with extra helper methods (I do not know the situation with current versions of a framework).
Thus straight usage of "for (key in dict)" would return all the elements of the div plus references to helper methods. Which is kind of unexpected :)
After testing out instasnceof I found that it will return true if the argument is an array or an object literal.
function test(options){
if(options instanceof Object){alert('yes')}//this will alert for both arrays and object literals
}
test({x:11})// alerts
test([11])// alerts as well but I do not want it to
Is there a way to test if the argument "options" is an object literal?
P.S. I am creating a module that will allow the user to access its configuration options, and I want to test if the argument is only an object literal or not?
is there a way to test if the argument "options" is an object literal?
No, because it makes no sense. You can test whether it's an object, but how it was created (via a literal in the call to your function, via a literal elsewhere, through new Object, by deserializing a JSON string, ...) is not information that's maintained.
after testing out instasnceof i found that it will return true if the argument is an array or an object literal
Correct. Arrays in JavaScript are objects (and not really arrays).
If you want to test that an object is a plain old object, you can do this:
if (Object.prototype.toString.call(options) === "[object Object]") {
// It's a plain object
}
But there's really no reason to do that. It's not your problem. As long as what they pass you has the properties you expect, don't try to limit the object further.
p.s. i'm making a module that will allow the user to pass it configuration options and i want to test to make sure that the argument is only an object literal.
Why? If the user wants to use an object that hasn't been declared as a literal right there and then, why would you care? If they want to use an object that they've created via a different constructor function (e.g., rather than just a plain object), again, why would you care?
function isPlainObject(o) {
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
}
However, you can't test wether o was declared as a literal or instantiated somehow else - you can just test whether it's a plain object without any constructor than Object.
If you're trying to forbid arrays, you can just do this:
var isObject = options instanceof Object;
var isArray = options instanceof Array;
if(isObject && !isArray)
{
alert('yes');
}
An alternative solution would be to use Lodash:
_.isPlainObject(value)
Here is the documentation:
https://lodash.com/docs/4.17.15#isPlainObject