Reputation: 15362
I asked earlier why backbone.js's _.isArray(arr)
function still returns true, even if I do something like,
var a = [];
a.something = "test";
Because I sort of expected it to be turned into an [object Object]
(not sure if that is the correct way to reference the object that gets made when you do var o = {}
, but I'm talking about the type of object you can use key: value pairs with. Any insight on how to refer to that object, is much welcome.
I received the answer that it is not changing what the data type of a
is, merely adding the property something
to it. I can see in the console that I get a.something = "test", but where is this stored? Is it in the array's prototype? (I'm pretty sure not). But what does it mean simply "add a property"?
var a = "";
a.asdf = "test";
a.zxcv = "test1";
won't return the property similarly because the string isn't an object, but a function should be an object, yet
var a = function(){};
a.asdf = "test";
a.zxcv = "test1";
console.log(a);
only returns
function (){
}
(It kind of looks like a string...) I don't know why I wouldn't be able to do var a = new Function()
(even though I've never seen it before); it returns the same as directly above. Also jslint says it's eval. Why..?
I'm just trying to figure out what is meant by "adding properties to objects" and where these properties "go", and why they act differently in different types of objects
Upvotes: 1
Views: 90
Reputation: 128991
In JavaScript, there are several primitive types, including undefined
, number
, and string
. There are also object
s. All objects have properties.
Every lowercase-o object was created from a constructor. In the case of object literal notation, the constructor was an implicit Object
. Arrays are objects too, but rather than being created with the Object
constructor, they're created with the Array
constructor. Functions are objects too, which have the Function
constructor.
When you see an array, you likely think of it as having numbered elements; 0, 1, 2, etc. In reality, an array is just another object, except that rather than using alphabetic property names, it uses numeric property names, and you don't use .
to access the elements.
In reality, arrays have some optimizations by browsers to make them faster than if you were using a different kind of object, but such optimizations will still retain the semantics described here.
The odd behavior with strings is because strings aren't objects, but there's some quirky boxing behavior that makes someString.property = value
not an error. Only objects can have properties and methods per se; but we all know that someNumber.toString()
is not an error. What's up there?
It turns out that in some cases, when you try to use a primitive as if it were an object, it will box up that primitive into an object. For example, when I call someNumber.toString()
, it will create an object with the Number
constructor, distinct from the primitive number. Then it looks up toString
in the normal way, executing it with this
set to the object.
When you set the property on the string, it was implicitly converted to a String
-constructor object for the purposes of that operation. It set the property on the String
object just fine; it's just that the boxing was temporary; the boxing does not persist in the variable holding the primitive string.
It's true that we rarely use new Function
, but if you do use it, it does exactly what it sounds like it does: it creates a new function. You can pass it a string, and that will be the body of the function. If you create a new function with a string body and then call it, that's not too far from eval
ing code. That's why JSLint marks it as an eval
.
When you log an object to the console, developer tools will usually show you the properties since that's usually the most important part of the object. Functions usually aren't assigned custom properties, so developer tools just go with the plain string representation, which usually just shows the function arguments and body. The string representation of a function isn't that unusual in not showing properties — toString
of a plain Object
will just return [object Object]
.
Surely this information clarifies many things, but it still doesn't explain this:
console.log(new Array() instanceof Object); // => true
Wha? The constructor of the array is Array
, not Object
! This is because of something called the prototype chain. It is what controls inheritance.
Every object has an internal property called [[Prototype]]
. There is no standard way to access it, although many browsers have a non-standard __proto__
property to access it. When you use new
to create an object, [[Prototype]]
is set to the prototype
property of the function used to create the object.
Let's say we have an object foo
that had a constructor of Foo
. When we access a property foo.bar
, it first looks up bar
in foo
's own properties. If it's not found there or undefined, it will look up bar
in foo
's [[Prototype]]
's own properties. If not found there, it will look up bar
in foo
's [[Prototype]]
's [[Prototype]]
, on and on, until it gets to a null
[[Prototype]]
. This is the functionality that allows inheritance.
In order to determine whether an object is an instance, isinstance
goes through the prototype chain to see if any of the [[Prototype]]
s match the prototype
of the function. It just turns out that if you traverse the prototype chain of an array, you'll hit Array
's prototype, Object
's prototype, and then null
. Therefore, isinstance
will yield true
in new Array() instanceof Object
.
You may be interested in the annotated ECMAScript 5 specification, which defines the language, and of course covers some of the specific algorithms used in detail. It won't lay everything out for you; some very insightful things are not explicitly described, but require piecing several bits together on your own. For that reason, you probably don't want to read it straight through unless you're trying to implement it yourself, but rather reference sections of it whenever there's some behavior you're curious about.
Upvotes: 3
Reputation: 2308
In javascript, array is just an object with preassigned keys from 0 to n number of values that you provide.
var x = ['a','b','c','d',234];
is exactly like
var x = {0:'a',1:'b',2:'c',3:'d',4:234,length:5};
and all array functions will work on it with array calls like this Array.prototype.sort.push(x,'sdfsd');
.
All methods/properties of Main Object are inherited by all arrays.
so when you assign a non numeric value to an array, lets say with 2 elements. It gets added like this...
var x =['a','Stack','flow',0];
--added value x.a = 'something';
it really looks like this now
var x = {
0:'a',
1:'Stack',
2:'flow',
3:'0',
a:'something'
}
however, to js x is still an array, and when you just run any function on x, a wont show up. Until you access it like x.a
.
x.hasOwnProperty('a'); //true
Object.keys(x); //listing all keys in object(array x)
// ["0", "1", "2", "3", "a"] !!!keys function returns an array consisting of all keys in an object.
Function Objects are Different they aren't just Objects with keys.
You can still assign stuff to them but they will return function only. You can access properties like x.a etc. But dont do it.
Summary
Everything inherits from Object
object and therefore can have properties and methods.
Arrays are specialized objects, called Array
which inherit methods/props from Object
, that store values in indexed keys named 0-n form. But again can have extra properties and methods due to inheritance, although the wont show up in array methods or properties.
Functions are Objects which inherits from function object
which inherits from Object
so functions(functionObjects) have properties from both. Functions have extra properties too like prototype and arguments.
When you write this:...
var x = new function anonymous/named (){}
3 things happen:
1. x = {};
2. function executes...if it has this.p = etcc...then x gets it and x become x= {p:'etc'}
3. x.proto = function.prototype
then if you look up a property or method in x and is not found there js will look if there is something in proto then which refers to function's prototype object it goes there and search there. That's how you have classes in Javascript.
Upvotes: 0