When I access arguments from inside called function in nodejs...
echo '!function(){ console.log(arguments) }(1,2,3)' | node
... it outputs an object ...
{ '0': 1, '1': 2, '2': 3 }
... but in google chrome ...
!function(){ console.log(arguments) }(1,2,3)
... outputs ...
[1, 2, 3]
Why is it not consistent? What other js environments have this different behaviour? Is it ok for me to use arguments? How can I ensure it is always an array before I use it?
There are no rules for console output. The output doesn't represent anything that has to do with the language standard.
If you create a program that logs values from within a JS program, you're free to display those values however you want.
The arguments object is the same in both places. Only how it's being displayed is different.
How can I ensure it is always an array before I use it?
It's never an array. It's always an array-like object. In both cases its showing a value at object members 0, 1 and 2. Just uses different display syntax to do it.
In Chrome, try creating an object like this:
var my_obj = {
"0": 1,
"2": 3,
"1": 2,
length: 3,
splice: function(){},
};
And the log it in the console. It'll probably look like an Array literal, though it's obviously not.
It's not an Array in the browser, either. The arguments object has actually been in JavaScript longer than Arrays have, and when Arrays were first added to JavaScript (back in its 1.1 days), they didn't update arguments to be an Array. They haven't done it since then either, because of worries about backward-compatibility. It shows up in some browser consoles as though it were an Array because the debug console knows that most people plan to treat it as one anyway.
But the arguments object is close enough to an Array that it's easy to convert. One way to do it is like this:
var args = Array.prototype.slice.call(arguments, 0);
Array.prototype.slice, like most of Array.prototype's methods, is written to be generic: you can call it on Objects that aren't Arrays, and as long as they have properties with numeric names and a length property that's a Number, it'll work. The arguments object has both of these things, so these functions will work on it.
The slice function returns an Array which is a shallow copy of whatever object was passed into it, starting and ending at whatever numbers you specify. We tell it to start at zero, and because we didn't say where to stop, it assumes we want it to stop at the end, wherever that might be. This way, we copy all of the elements of arguments into a new Array, and now you can do whatever other Array things you want with it.
Related
In python, a list, even when it is a class, prohibits its instances from creating more user attributes.
>> x = list()
>> x.new_attribute = 90
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'new_attribute'
This as expected throws error even when classes could possibly accept more attributes through __dict__. This makes sense.
Even though it isn't exactly similar, my questions is that javascript arrays act weirdly when they are given properties.
let x = [1,2,3]
x.foo = "this is unexcpected"
console.log(x)
This would print [1, 2, 3, foo: "this is unexcpected"]. Here is my questions, Aren't arrays supposed to have all their keys to be autogenerated numbers? I mean if I check the length it is still three and it isn't counting foo as part of the array in the usual sense, more over all the methods like pop doesn't apply to the key-value pair. This makes a good sense, but makes me wounder if this (addition of key-value pairs) is allowed so that they could be used to store metadatas about the arrays, after all length is also kind of a property. One more questions, if arrays can store key-value pairs, what makes them different from object except some of the methods like inserting, poping ...?
I know this thread is old, but I find the question interesting...
The main part of the question is what's the difference between an object and an array. As mentioned in the comments, Array.prototype IS an object. Which allows us to do some kind of weird things. Take this code for example:
let y = [0,1,2,3];
y.foo = "Testing";
console.log(y);
y.sample = function(){
console.log("Hello world");
}
y.sample()
Yes, you can add methods to an array, on the console it outputs this:
> (4) [0, 1, 2, 3, foo: 'Testing']
0: 0
1: 1
2: 2
3: 3
foo: "Testing"
sample: ƒ ()
length: 4
[[Prototype]]: Array(0)
> Hello World
Considering the way that Javascript was made, we can do odd things like add methods to arrays and treat them as objects. However, these objects have intended uses and built-in methods provided by the developers (push, pop, etc.). Maybe you could create your own modified datatype in JS by modifying the Array.prototype object. Outside of that, it feels kinda weird to add methods and properties to arrays...at that point just make an object for the sake of readability, but hey, as long as your code is understandable and it works, it's good to me.
Recently i was experimenting with array push() method in javascript.
I created an array, and pushed the same array using push method.
var a=['hello', 4]
a.push(a)
the result was surprising, when i explored the array items in chrome console, there was infinite array produced. i want to know why this is happening. As the push() method adds the element on last.
I was expecting this result
['hello, 4, ['hello',4]]
but the result was something else, here is the screenshot of chrome console
problem screenshot, infinite inner arrays using push method in JavaScript
When you assign an object to a variable in Javascript (and indeed in most similar languages), that variable holds what is called a "reference" to that object. Note that arrays in JS are objects, but primitive values like strings and numbers are not.
One consequence of object assignments being "by reference" is that any change you make to that object - even if its done to another variable that happens to reference the same object - will "show up" when you inspect the original variable.
So here, you start off with
var a=['hello', 4]
And then do
a.push(a)
then the object (array) to which a points has been changed. It now has an additional element on the end - which is a, the very same array we're talking about.
So it expands recursively:
a = ['hello', 4, a]
= ['hello', 4, ['hello', 4, a]]
= ['hello', 4, ['hello', 4, ['hello', 4, a]]]
...
And so on, infinitely. This doesn't require an infinite amount of memory, because the third element of the array is simply a reference to the memory location which holds the array.
The explanation for a dense array that I read from a few pages seem to be in contradiction to one another. I'd like some help understanding what it is.
While some links (search result 1, search result 2) suggest that it simply is an array where:
the elements of the array are known to be specific values; and
are assigned to the array at the time of its initialization.
The allusion there is that JavaScript arrays are dense.
It all makes sense up until here.
But this statement taken from the JavaScript Guide on the Mozilla Developer Network (MDN) says:
Since an array's length can change at any time, and data can be stored at non-contiguous locations in the array, JavaScript arrays are
not guaranteed to be dense; this depends on how the programmer chooses
to use them. In general, these are convenient characteristics; but if
these features are not desirable for your particular use, you might
consider using typed arrays.
And this has confused me now. My question is:
What does the statement on the MDN page mean when it says JavaScript arrays are not guaranteed to be dense? If it means that the following is not a dense array because one or more of its elements are undefined at the time of initialization, then why do the links I listed above seem to indicate that JavaScript arrays are indeed dense?
var array = new Array(1, , 3, ); // [1, undefined, 3, undefined]
"Dense" is in opposition to "sparse", and generally is used when talking about storage. For example, this array is dense:
a = [undefined, undefined, 2]
It can be stored in memory exactly like that: a sequence of three locations, the first two being undefined, the third being 2.
This array is sparse:
a = []
a[100000000] = 100000000
It is not stored in memory as a sequence of 100000001 locations, as it would be horribly inefficient. It is definitely not 100000000 places of undefined followed by 100000000. Rather, it just says 100000000th one is 100000000, and there is no space allocated to the first 100000000 elements.
(Actually, try to do this with 2 instead of 100000000, and you'll notice a curious thing: Chrome will display the dense array as [undefined, undefined, 2], but the sparse one as [undefined × 2, 2].)
Those articles say you can create an array being dense. This means that, at the time of creation, such arrays are dense, since in arrays like:
var a = new Array("foo", "bar", "baz");
var b = [2, 3, 5];
every element is set: from 0 to length-1, there is no undefined value. Or better said: every position from 0 to length-1 was assigned a value (even if the value is, actually, undefined).
However, you can make those arrays not dense anymore, by doing something like this:
a[20] = "bat";
That array, which was dense, is not dense anymore since the elements 0 1 2 and 20 (unlike elements in 3 to 19) are set to a value (this array has 4 elements, not 21).
I was wondering if any one knows how memory is handled with JS arrays if you have an array that starts with a high value.
For example, if you have:
array[5000] = 1;
As the first value in the array, everything before 5000 simply does not exist, will the amount of memory assigned to the array cater for the unassigned 4999 positions prior to it... or will it only assign memory to the value in the array for [5000] ?
I'm trying to cut down on the amount of memory used for my script so this led to me wondering about this question :)
When assigning a value to the 5000th key, not the whole array is populated:
var array = []; // Create array
array[5000] = 1;
'1' in array; // false: The key does not exists
Object.keys(array); // 5000 (it's the only key)
If you want to blow your new browser with arrays, populate a typed array:
var array = new ArrayBuffer(6e9); // 6 Gigs
Both can be verified easily in Chrome: Open the console and memory console (Shift+Esc), and paste the code. window.a=new Array(6e9); or window.a=[];window[6e9]=1; doesn't result in a significant memory increase,
while window.a=new ArrayBuffer(6e9); crashes the page.
PS. 6e9 === 6000000000
Javascript is really interpreted and run by the browser, so it depends on how the browser implements this behavior. In theory, once you do array[5000], you have an array of 5001 elements, all except the 5001st being undefined.
Though if I were the one implementing the logic for running such script, undefined would be the default value if not assigned to anything else, meaning I could probably get away with defining a map with 1 entry assigning key 5000 to value 1. Any accesses to any other value in the array would automatically return undefined, without having to do unnecessary work.
Here's a test of this here. As you can see, the alert is seen immediately.
JS arrays are actually not arrays as you know them from other programming languages like C, C++, etc. They are instead objects with a array like way of accessing them. This means that when you define array[5000] = 1; You actually define the 5000 property of the array object.
If you had used a string as the array key you would have been able to access the index as a property as well to demonstrate this behavior, but since variable names can't start with a number array.5000 would be invalid.
array['key'] = 1;
alert( array.key ); // Gives you 1
This means that arrays will probably be implemented much like objects, although each implementation is free to optimize, thus giving you the behavior you except from objects where you can define object.a and object.z without defining the whole alphabet.
Namely, how does the following code:
var sup = new Array(5);
sup[0] = 'z3ero';
sup[1] = 'o3ne';
sup[4] = 'f3our';
document.write(sup.length + "<br />");
output '5' for the length, when all you've done is set various elements?
My 'problem' with this code is that I don't understand how length changes without calling a getLength() or a setLength() method. When I do any of the following:
a.length
a['length']
a.length = 4
a['length'] = 5
on a non-array object, it behaves like a dict / associative array. When I do this on the array object, it has special meaning. What mechanism in JavaScript allows this to happen? Does JavaScript have some type of property system which translates
a.length
a['length']
into "get" methods and
a.length = 4
a['length'] = 5
into "set" methods?
Everything in JavaScript is an object. In the case of an Array, the length property returns the size of the internal storage area for indexed items of the array. Some of the confusion may come into play in that the [] operator works for both numeric and string arguments. For an array, if you use it with a numeric index, it returns/sets the expected indexed item. If you use it with a string, it returns/sets the named property on the array object - unless the string corresponds to a numeric value, then it returns the indexed item. This is because in JavaScript array indexes are coerced to strings by an implicit toString() call. Frankly, this is just one more of those things that makes you scratch your head and say "JavaScript, this, this is why they laugh at you."
The actual underlying representation may differ between browsers (or it may not). I wouldn't rely on anything other than the interface that is supplied when working with it.
You can find out more about JavaScript arrays at MDN.
Characteristics of a JavaScript array
Dynamic - Arrays in JavaScript can grow dynamically .push
Can be sparse - for example, array[50000] = 2;
Can be dense - for example, array = [1, 2, 3, 4, 5]
In JavaScript, it is hard for the runtime to know whether the array is going to be dense or sparse. So all it can do is take a guess. All implementations use a heuristic to determine if the array is dense or sparse.
For example, code in point 2 above, can indicate to the JavaScript runtime that this is likely a sparse array implementation. If the array is initialised with an initial count, this could indicate that this is likely a dense array.
When the runtime detects that the array is sparse, it is implemented in a similar way to an object. So instead of maintaining a contiguous array, a key/value map is built.
For more references, see How are JavaScript arrays implemented internally?
This really depends on what you intend to do with it.
[].length is "magical".
It doesn't actually return the number of items in the array. It returns the largest instated index in the array.
var testArr = []; testArr[5000] = "something"; testArr.length; // 5001
But the method behind the setter is hidden in the engine itself.
Some engines in some browsers will give you access to their implementations of those magic-methods.
Others will keep everything completely locked down.
So don't rely on defineGetter and defineSetter methods, or even, really, __proto__ methods, unless you know which browsers you know you're targeting, and which you aren't.
This will change in the future, where opt-in applications written in ECMAScript Next/6 will have access to more.
ECMAScript 5-compliant browsers are already starting to offer get and set magic methods in objects and there's more to come... ...but it's probably a while away before you can dump support for oldIE and a tonne of smartphones, et cetera...
It is important to know that when you do sup['look'] = 4; you are not using an associative array, but rather modify properties on the object sup.
It is equivalent to sup.look = 4; since you can dynamically add properties on JavaScript objects at any time. sup['length'] would for an instance output 5 in your first example.
To add to tvanfosson's answer: In ECMA-262 (the 3.0 specification, I believe), arrays are simply defined as having this behavior for setting properties (See 15.4.5.1). There's no general mechanism underlying it (at least as of now) - this is just how it's defined, and how JavaScript interpreters must behave.
As other people have mentioned, a property in JavaScript can basically act as both as getter and a setter of your array (or string or other inputs).
As a matter of fact, you might try this yourself:
const test = [1, 2, 3, 4, 5]
test.length = 3
console.log(test) // [1, 2, 3]
test.length = 5
console.log(test) // Guess what happens here!
As far as I know, arrays in JavaScript do not work exactly like associative arrays and you have elements which are put in memory as contiguously as possible (given that you can have arrays of mixed objects), depending on the JavaScript engine you are considering.
As a side note, I am a bit baffled that the most voted answer keeps spreading the over-simplified myth (or half-truth) of "everything being an object in JavaScript"; that is not exactly true, otherwise you will never study primitives, for example.
Try to do this:
const pippi = "pippi"
pippi.cat = "cat"
console.log(pippi.cat) // Will it work? Throw an error? Guess why again
Spoiler: the string is wrapped in a throwaway object for that specific operation on the second line, and then in the following one you are just going to access a property of the primitive which is not there (provided you did not play with String.prototype or the like), so you get undefined.
Array object inherits caller, constructor, length, and name properties from Function.prototype.
A JavaScript array is an object just like any other object, but JavaScript gives it special syntax.
arr[5] = "yo"
The above is syntactic sugar for
arr.insert(5,"yo")
which is how you would add stuff to a regular object. It's what is inside the insert method that changes the value of arr.length
See my implementation of a customArray type here: http://jsfiddle.net/vfm3vkxy/4/