I am aware that the for in loop can help iterate through properties of objects, prototypes and collections.
The fact is, I need to iterate over String.prototype, and though console.log(String.prototype) displays the complete prototype, when I do
for (var prop in String.prototype) {
console.log(prop);
}
to display the name of the elements in the prototype, it displays nothing, as if it were empty.
Do the JavaScript engines hide the basic prototypes methods, or am I doing something wrong?
The specification says:
If the value of an attribute is not explicitly specified by this specification for a named property, the default value defined in Table 7 is used.
Table 7 — Default Attribute Values
...
[[Enumerable]] false
So it is not enumerable (as with all built-in properties).
Like others have said, all properties in String.prototype are non-enumerable. To get a list of all the properties, including non-enumerable, use Object.getOwnPropertyNames() (newer browsers only)
Native methods aren't visible through an for(prop in obj) iteration.
It's possible to find properties when you loop through a built-in object. In this case, the page has extended the prototype with a custom method. Frameworks (such as jQuery) often modify built-in objects in this way.
Related
With javascript is it possible to console.log or list the .prototype properties associated with an object of a given type?
I'm using a firebase cloud-firestore and would like to see what exists on the prototype for calls to the database.
For example a db call returns an Object of type QuerySnapshot { ... }. I'd like to see what exists on QuerySnapshot.prototype.
I can map through the returned values using .map, but if I console log out the object, it's not an array, so presumably it is inheriting a custom .map from prototype?
Yes, you can use Object.getPrototypeOf to get an object's prototype, Object.getOwnPropertyNames to get its properties that have string names, and Object.getOwnPropertySymbols to get its properties that have Symbol names. You might want to repeat the process (going to the prototype's prototype and so on) to get the properties at every level.
The advantage to getOwnPropertyXYZ is that it includes properties that are non-enumerable, whereas for-in and Object.keys only return enumerable properties. (They also don't include Symbol-named properties.)
Alternately, you can console.log the object and explore its properties with the browser's interactive object explorer in the devtools.
I know that all object properties have a name and have attributes like value, configurable, enumerable and writable. But in this post I read that objects too have attributes like prototype, class and extensible.
I understand that prototype attribute is for pointing for the parent object. But what I don't understand is what's class attribute? Is there such attribute? And isn't extensible is a method of object as isExtensible() ?
In this post I read that objects too have attributes like prototype, class and extensible.
They're not called "attributes" normally but internal slots. Usually they are denoted by double brackets to differentiate them from normal properties, i.e. [[prototype]], [[class]] and [[extensible]].
What is the [[class]] attribute? Is there such attribute?
Not in ES6 any more. The [[class]] internal slot contained information on which kind of builtin type (e.g. Array, RegExp, builtin wrapper) the object was. It was shown when you used the Object.prototype.toString method on the object. (Have a look at Why can Object.prototype.toString.call(foo) detect foo's type? or Why does `Object.prototype.toString` always return `[object *]`? for more details - it was also the best way to detect whether an object is an array before Array.isArray was available).
Since ES6, there is no such internal slot any more and Object.prototype.toString relies on the Symbol.toStringTag mechanism now.
And isn't extensible a method of object as isExtensible()?
No, the [[extensible]] internal slot is the thing that isExtensible() accesses, and that Object.preventExtensions() can set.
Sometimes I run the following on JSON string objects:
for(var i in JSONObject){
....
}
Do I need to run .hasOwnProperty here? I assume since JSON isn't extended from a parent object, it is safe to assume all its properties are its own.
I assume since JSON isn't extended from a parent object, it is safe to assume all its properties are its own.
That's not quite right. Unless an object was created via Object.create(null), it has Object.prototype in its prototype chain. Properties such as hasOwnProperty, that you mentioned, or toString are defined there. So, most objects have more than just "their own" properties, that includes objects that have been created from JSON via JSON.parse.
However, all standard properties defined on Object.prototype, are not enumerable and hence won't appear in a for..in loop.
So, should you use hasOwnProperty? As so often: It depends.
If you are sure that no code that you use, be it your own or third-party code, adds enumerable properties to Object.prototype, then there is no reason to use hasOwnProperty in the loop.
If you are not sure about it then you might want to use hasOwnProperty, but it would be better to simply not extend Object.prototype with enumerable properties and avoid third-party code that does.
Related:
How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop
I ran a couple of tests on this and JSON strings won't transmit inherited properties. So let's say you have an API response from an endpoint that looks like this after you prettify it:
{
"one": "blue",
"two": "watermellon",
"three": "lalal",
"four": "value"
}
If you run a for(var i in JSONObject) loop over the parsed value of the above, you'll only ever find four properties associated with the object as long as you didn't explicitly attach any properties to the parent Object literal (Object.prototype) in your current environment.
This question already has answers here:
Why is it possible to query jQuery('div') like an array?
(5 answers)
Closed 9 years ago.
Just like $ itself is not simply a user defined object (it is, at its base, a function and that is why you can use the () operator on it and it inherits all the functions from Function.prototype) what is the actual Javascript type of the so-called jQuery object?
It has to be one of the standard array-like objects because you can use the [] operator on it, something you can't even do on strings in IE8 (and no, you can't, not on the Object String. You can on string literals before they're boxed).
So again, its not a user defined object (NB there's no such thing as a jQuery object, its written in raw javascript somewhere along the line). I have a feeling its a NodeList (or equivalent in browsers that don't have NodeList).
A reason you might have noticed this is you've added methods to the Array prototype, and you discover the function doesn't exist on a set of nodes found by jQuery!
So is anyone intimate with jQuery enough to share this lower level info with me? Or is there a short, exhaustive list of array-like objects in Javascript that I can test the jQuery object against till I find out which one it is myself?
The reason I ask this, instead of assume that jQuery is just adding elements to the object, using indexes as property names (I.e. obj[0] = x;) is because of how the Chrome dev tools and Firebug display them.
This shows dev tools displaying Array, jQuery and Array-like objects, and that there is at least some magic behind what jQuery is doing.
EDIT
It's not a NodeList. If it helps; inspecting it in Chrome shows that it is of type jQuery.fn.jQuery.init[0] with a __proto__ describing itself as Object[0] (which has all the jquery methods). Anyone explaining what and how jQuery is doing would be greatly thanked. I'm going to look at jQuery's source now.
And as for the image, it isn't simply an overridden .toString().
$('').toString == Object.prototype.toString //true
$('').toString == Array.prototype.toString //false
What is a jQuery object?
The $() or jQuery() function returns a jQuery object. It is not an Array and not a NodeList, and not in any way derived from either of those. It is an Object created with the jQuery constructor (which is actually the jQuery.fn.init() function). This object is very much like any other Object created with new SomeConstructor(), or even a plain object literal.
When you call $() or jQuery() without a new operator, it automatically does a new for you:
jQuery = function( selector, context ) {
// The jQuery object is actually just the init
// constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
The jQuery object is somewhat "array-like" in that it has properties with numeric indexes and a .length property, but these are just properties set directly in the object in the jQuery code. It also has a number of properties and methods that come from its prototype, which is jQuery.fn or jQuery.prototype (jQuery.fn is merely a reference to jQuery.prototype; they are the same object.)
You can see an example of this in the jQuery code that wraps a DOM element when you use $(element):
// HANDLE: $(DOMElement)
} else if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} ...
In this bit of code, selector is actually a DOM element, and the code stores that element in this[0] and sets this.length to 1. This is why you can use [0] and .length, simply because the object has these properties that were explicitly set.
Why does a jQuery object display like an Array?
There is some magic involved here, but the magic is in Firebug and the Chrome Developer Tools. They both look for two specific properties to decide to display an object as if it were an array:
A length property which is either a number or a string containing a number.
A splice property which is a function.
If the object has both those properties, it is displayed as an array.
You can test this by pasting the following line into either the Chrome DevTools or Firebug:
({ splice:function(){}, length:0 })
Chrome displays:
[]
Firebug displays:
Object[ ]
Remove either property and it will display as an object.
It doesn't matter if these properties are in the object itself or its prototype. You can paste this code into either console and it will display the same array-like notation as the code above:
function A(){}; A.prototype = { splice:function(){}, length:0 }; new A;
You can add an element to your "array":
({ splice:function(){}, length:1, 0:'test' })
Now Chrome displays:
["test"]
and Firebug displays:
Object[ "test" ]
Note that the Firebug display is not exactly the same as what it displays for an actual Array. Firebug puts that Object prefix in front of the array-like display to let you know that it's not an actual Array.
It does that on jQuery objects too. If you enter:
$(document.body)
Firebug displays:
Object[ body ]
You can click the word Object to get the full object-style display of the jQuery object instead of the array-like display.
Chrome doesn't make this distinction; it displays an Array or an array-like Object the same way.
So there's the magic. It's really nothing special in jQuery, except that the object it returns does have the length and splice properties. The splice() method is on the prototype and the length property may come from the prototype (for an empty "array") or more often from the jQuery object itself.
Those two properties trigger the real magic: a hack in the DevTools and Firebug to try to provide a more useful display for objects like these.
Bragging rights :-)
A bit of historical trivia: I was actually responsible for this part of jQuery's architecture. The very first version of jQuery in early 2006 didn't work like this. The jQuery object didn't have a .length and [0], [1], etc. properties. Instead it had a "private" array of its own, and you had to use .get(n) to fetch values from that array.
I thought it would be more convenient to have direct array-like access to the elements and came up with the idea of setting the .length, [0], [1], etc. properties so it would work like a read-only array.
my understanding is a sub class of Array, which inherited from Array Class and has its own method
changes above:
it's not sub class of Array. But it made from Array, but after Array object created, jQuery alter the object prototype with jQuery its own prototype,then finally it become jQuery object which is Array-like object.
A clientside javascript library I've developed uses objects as hashes in some areas. It loops through objects parsed from Json data with a for...in loop using the property name as a key. eg... (pseudo code)
var conversations = {'sha1-string':{name:'foo',messages:[]}}
for(var id in conversations){
console.log(id);
console.log(conversations[id].name);
}
Unfortunately MooTools (and Prototype, etc) add methods to the global namespaces, so my for...in loops now iterate through MooTools' additions (eg. limit, round, times, each), causing errors when it applies logic to them as if it were the data expected.
As it's a library, I have to expect that it will be used with MooTools, Prototype, etc. Is there an easy way around this problem? My current solution is just to pass the object to a method which strips out the MooTools specific entries and returns the clean object, but this means also checking what Prototype and all similar libraries out there add, and seems to be a backwards way of doing things.
My other solution is to stop relying on the property name as a key, and perform validation in the loops to ensure I'm looking at the data I want to. Before I do that rewriting though, I'm wondering if anyone has a better/existing solution?
Thanks :)
If your clientside objects are not inherited from other custom objects, you see if you could use the javascript's Object.hasOwnProperty method to find out if a certain property exists in the object itself and not up in the inheritance chain via the prototype object.
For browsers that don't support this method, you can write a wrapper around to check:
var hasOwnProperty = function(object, property) {
if(object.hasOwnProperty) {
return object.hasOwnProperty(property);
}
var prop = object[property];
return typeof(prop) !== "undefined" && prop !==
object.constructor.prototype[property];
}
How to use it:
for(var key in someObj) {
if(hasOwnProperty(someObj, key)) {
// we are good to go!
}
}
If I got it correctly, you are looking for the hasOwnProperty() method.
As "limit", "round", "times" and "each" are all additional methodes of the Array prototyp you're main failure is to use "for in" to iterate over arrays. You should check the type of the object before and use "for in" only for objects and "for" for arrays.
Btw. "for in" is the slowest method to iterate over arrays.
Using both MooTools and Prototype isn't a very good idea as they modify the base prototypes and can't co-exist peacefully. That said, none of them modify Object.prototype (not anymore) so you should not see any other properties besides your own.
Did you add a plugin which is perhaps adding these properties there? Could you give a more complete example that shows where these properties are getting listed and also the versions of these libraries that you are using?
hasOwnProperty checks will solve the prototype problem, but this shouldn't be needed in the first place, so maybe it's better to find out exactly which script is messing up.
MooTools has created a Hash type just because they didn't want to modify Object.prototype. Here's a quote from the docs:
Hash
A custom Object ({}) implementation which does not account for prototypes when setting, getting, or iterating. Useful because in JavaScript, we cannot use Object.prototype. Instead, we can use Hash.prototype!