In a script I saw this:
function addToPoint(x, y) {
x = Math.floor(x/SCALE);
y = Math.floor(y/SCALE);
if (!points[[x,y]]) {
points[[x,y]] = 1;
} else if (points[[x,y]]==10) {
return;
} else {
points[[x,y]]++;
}
drawPoint(x*SCALE,y*SCALE, points[[x,y]]);
}
So what's happening, I think, is this:
points[[x,y]] = 1;
Here, the guy dynamically creates a field for the points-object (which was declared empty). By passing it like this, it gets converted to a string and the x and y params of the function will make up that field.
So, in effect, if i called addToPoints(3,4) the code results in this:
points["3,4"] = 1;
This is really weird to me: is [x,y] a legit array? What kinda notation is that? What's the rule behind that??
I played around with the code a bit and it seems like you can declare an array in JavaScript just by doing this:
[x,y];
Help, tips and clarification appreciated!
var arr = [ x, y ]; is simply how you declare an array in JavaScript with x and y as the first and second elements.
The second part points[[x,y]] is a little more confusing. Basically what happens is that the arr array gets converted into a string (something like [ 1, 2, 3 ] will become "1, 2, 3") which will then be used as the property name on the points object.
A little less terse (and with actual numbers instead of the x and y parameters) what happens looks somewhat like this:
var points = {};
var arr = [ 1, 3 ];
var key = arr.toString(); // '1, 3'
points[key] = 1; // { "1, 3": 1 }
I believe what you miss here is the fact that when you use something as a property name on a project it being converted to the string:
points[[x,y]]
really doing
points[[x,y].toString()]
You can try to test it with
points[{}]
it will create key [object Object]
Reason to use it is that there is no support for two-dimensional arrays in javascript, however you can have array of arrays
And this little trick allow to use one dimensional array as a two-dimensional.
Here is funny trick:
Array.prototype.toString = function ( ) { return this.join(':') }
Now
points[[x,y]] = 1
will create key x:y and not x,y
Related
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?
See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));
Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm
By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)
Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]
var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);
How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)
Yes I know how to loop through arrays (types) in Javascript. The fact is, I'd like to know how to set a multiDimensionalArray array's value by a set of given indexes to keep it as generic as possible. For example I've an array with a length of 3 (which could as well be a length of 4, 100, ...):
var indexes = [0, "title", "value"];
I know the multidimensional array (mArray) can be set by putting the indexes like so:
multiDimensionalArray[0]["title"]["value"] = "Jeroen"; or multiDimensionalArray[indexes[0]][indexes[1]][indexes[2]] = "Jeroen";
The fact that the given indexes array can vary and does not always contain the same index names so I'm search for a solution like this:
multiDimensionalArray[indexes] = "Jeroen";
I don't know how to code the assignation if this. I've searched on Google/Stack Overflow. Maybe I'm using the wrong keywords. Can anyone help me?
Thanks!
Following example is how I've made it working thanks to Jonas's example:
var json = [{
"hello": {
"world": 1,
"world2": 2
},
"bye": {
"world": 1,
"world2": 2
}
}];
var indexes = [0, "hello", "world2"];
var value = "value";
indexes.slice(0,-1).reduce((obj, index) => obj[index], json)[indexes.pop()] = value;
console.log(json);
So imagine you have a structure like this:
var array=[[["before"]]];
Then you want
var indexes=[0,0,0];
var value="value";
to actually do:
array[0][0][0]="value";
which can be easily achieved with reduce:
indexes.slice(0,-1).reduce((obj,index)=>obj[index],array)[indexes.pop()]=value;
Explanation:
indexes.slice(0,-1) //take all except the last keys and
.reduce((obj,index)=>obj[index] //reduce them to the resulting inner object e.g. [0,0] => ["before"]
,array) //start the reduction with our main array
[indexes.pop()]=value;// set the reduced array key to the value
var array=[[[0]]];
var indexes=[0,0,0];
var value="value";
indexes.slice(0,-1).reduce((obj,index)=>obj[index],array)[indexes.pop()]=value;
console.log(array);
I am in bit of a puzzle, recently I had worked on a project where use of javascript was necessary. Everything is working fine I just need to know how does it work
eg : I had a dynamic variable count, which use to get some value, lets say I get the value as var count = 6;
Now when I put this in array {count : count }
I get the output as {count : 6}
Now my doubt is the output should have been { 6 : 6} as count should have been replaced with its value but it didn't happen so. Why is happening ? and how is this working properly ?
The key value pairs treat the key as a literal and the value as a variable.
so:
var count = 6;
var o = {count: count}; // results in {count: 6}
but to use a variable as the key, you can do this:
var count = 6;
var o = {};
o[count] = count; // results in: {6: 6}
The JavaScript object initialisation syntax lets you use bare words. If you do this:
{ foo: 6, bar: 12 }
It's equivalent to this:
{ 'foo': 6, 'bar': 12 }
What you want is to assign directly, like so:
var foobar = {};
foobar[foo] = 6;
foobar[bar] = 12;
In JavaScript associative arrays (or most associative arrays for that matter), the left side is the key, and the right side is the value. -> {key:value}
When you put {count:count} when you have a count variable beforehand (let's say its value is 10), what will happen is it will be read as {count:10}.
The left-hand side, or the key, is not a variable, but a constant.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?
See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));
Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm
By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)
Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]
var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);
How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)
Code:
var testarray = [];
var test1 = "ashutosh";
var test2 = "ashutosh2";
if (test1 != test2) {
testarray.push = "ashutosh3";
testarray.push = "ashutosh4";
alert(testarray.length);
}
if (testarray.length != 1) {
alert(testarray.length);
alert(testarray[testarray.length - 1]);
alert(testarray[testarray.length - 2]);
}
But when all the alerts are showing up undefined. I have no clue why is this happening.
push is a function, not a property, so instead of
testarray.push="ashutosh3";
it's
testarray.push("ashutosh3");
Here's how I'd update that code, FWIW, but I think the only substantive change is doing the push correctly and using >= 2 rather than != 1 in the length check at the end (since otherwise if the array is empty you're looking at entries -1 and -2, which will be undefined):
var testarray = [];
var test1 = "ashutosh";
var test2 = "ashutosh2";
if (test1 !== test2) {
testarray.push("ashutosh3");
testarray.push("ashutosh4");
alert(testarray.length);
}
if(testarray.length >= 2) {
alert(testarray.length);
alert(testarray[testarray.length-1]);
alert(testarray[testarray.length-2]);
}
T.J. Crowder already answer the issue with push but I'm guessing you are new to JavaScript so here are some useful tips I wished knew earlier.
For Each Loops
Instead of writing a standard for loop, you can use a forEach loop.
for( i in testArray ){
console.log( i );
}
Objects
Till hashtables and modules make their appearance to JS, we are left with using arrays. Here is the easiest method I know of to make an object.
var ArrayUtils = {
"print" : function(array) {
console.log(array);
}
}
Since ArrayUtils is an list, you can extend it using either dot or bracket notation
ArrayUtils["size"] = function(array){
return array.length;
}
ArrayUtils.indexOf = function(array, i){
return array[i];
}
Higher-Order Functions
Arrays in JavaScript come with a built-in map, reduce and filter functions. These three functions are highly useful when it comes to writing elegant code.
Map, passes each element in an sequence into a function
testArray.map( function(i){ console.log(i); } );
Reduce, well reduces the array into a single value. In this example i'm calculating the sum of the array
testArray.reduce( function(x,y) { return x+y; } );
Filter, as you could guess removes elements from an array. In JS, .filter() returns a new array
testArray = testArray.filter( function(i) { return ( i > 0 ); } );
I also read that JS has iterator and generator support. They are powerful iteration tools and worth checking out if you are going to heavily use iteration in your code base. I don't so, it's been something I put off as a todo.