JavaScript setting variables? - javascript

Can someone explain the second line of this function? is it setting two variables to = 0 at one time? i.e. var i = 0 and var res = 0? If so, is it necessary to set var i = 0 considering that it does that in for(i = 0 ... etc
function sumOnSteroids () {
var i, res = 0;
var number_of_params = arguments.length;
for (i = o; i < number_of_params; i++) {
res += arguments[i];
}
return res;
}

No, the value of i will be undefined, the initializer only applies to "res" in that case. To assign the value you'd need:
var i = 0,
res = 0;

It is setting two variables at once with the var keyword being applied to both, scoping them. Without the var, they would be properties of window (essentially globals).
The first one (i) would be undefined and the second one (res) would be 0.
This is a powerful pattern because...
var should be implicit, but it is not, so we only have to repeat it once.
Less typing for you.
Better for minifying (smaller file size).

Related

Number prototype

Hi everyone i need an help.
I try to modify Number.prototype to add the function sum.
I want to add some numbers to my initial number.
Number.prototype.sum = async (...nums) => {
var x = //What I have to write to have my inizial number here?
for (var i = 0;i<nums.length;i++) {
x=x+nums[i]
}
return x
}
console.log((10).sum(2)) // output: 12
console.log((10).sum(4,6)) // output: 20
(I use visual studio code and the hint after this. is only number)
I tried with:
Number.prototype.valueOf(this)
Number.prototype.valueOf(this.number)
Number.parseInt(this.toString())
Number.parseFloat(this.toString())
Number.parseInt(this.number.toString())
Number.parseFloat(this.number.toString())
this.valueOf()
this.number.valueOf()
You have to use function to access the correct this context (which is the number that the method is called on). Arrow functions inherit their this context from the parent scope (the global object in this case). Also async is not needed since you are not doing anything asynchronous here:
Number.prototype.sum = function (...nums) {
var x = this
for (var i = 0; i < nums.length; i++) {
x = x + nums[i]
}
return x
}
console.log((1).sum(2, 3))
Aside from the fact that augmenting native prototypes is a bad idea, wouldn't you think that a function like this is better suited for the Array prototype?

Cannot set property '0' of undefined in 2d array

I know this has been asked a lot of times, but how do I fix exactly this thing?
I have a map[][] array (contains tile ids for a game) and I need to copy it to pathmap[][] array (contains just 0's and 1's, it is a path map), however when I do so..
function updatepathmap(){
pathmap = [];
var upm_x = 0;
while (upm_x < map.length){
var upm_y = 0;
while (upm_y < map[upm_x].length){
pathmap[][]
if (canPassthrough(map[upm_x][upm_y])) {
pathmap[upm_x][upm_y] = 1;
} else {
console.log(upm_x);
console.log(upm_y);
pathmap[upm_x][upm_y] = 0;
}
upm_y++;
}
upm_x++;
}
console.log(map);
console.log(pathmap);
}
..it gives me Cannot set property '0' of undefined typeerror at line pathmap[upm_x][upm_y] = 0;
Despite the foo[0][0] syntactic sugar, multi-dimensional arrays do not really exist. You merely have arrays inside other arrays. One consequence is that you cannot build the array in the same expression:
> var foo = [];
undefined
> foo[0][0] = true;
TypeError: Cannot set property '0' of undefined
You need to create parent array first:
> var foo = [];
undefined
> foo[0] = [];
[]
> foo[0][0] = true;
true
You can determine whether it exists with the usual techniques, e.g.:
> var foo = [];
undefined
> typeof foo[0]==="undefined"
true
> foo[0] = true;
true
> typeof foo[0]==="undefined"
false
I would have thought pathmap[][] was a syntax error, I'm surprised you're not seeing one.
Before you can use an array at pathmap[upm_x], you must create an array at pathmap[upm_x]:
pathmap[upm_x] = [];
This would be the first line in your outer while, so:
while (upm_x < map.length){
pathmap[upm_x] = [];
// ...
Remember that JavaScript doesn't have 2D arrays. It has arrays of arrays. pathmap = [] creates the outer array, but doesn't do anything to create arrays inside it.
Side note:
var upm_x = 0;
while (upm_x < map.length){
// ...
upm_x++;
}
is an error-prone way to write:
for (var upm_x = 0; upm_x < map.length; upm_x++){
// ...
}
If you use while, and you have any reason to use continue or you have multiple if branches, it's really easy to forget to update your looping variable. Since looping on a control variable is what for is for, it's best to use the right construct for the job.
Side note 2:
Your code is falling prey to The Horror of Implicit Globals because you don't declare pathmap. Maybe you're doing that on purpose, but I wouldn't recommend it. Declare your variable, and if you need it outside your function, have your function return it.
Side note 3:
map would make this code a lot simpler:
function updatepathmap(){
var pathmap = map.map(function(outerEntry) {
return outerEntry.map(function(innerEntry) {
return canPassthrough(innerEntry) ? 1 : 0;
});
});
console.log(map);
console.log(pathmap);
}

Object.create to create an object with costructor

I am learning Javascript and I am a C++ programmer. I have tried creating an object with a constructor with object.create and here is the result:
var PlayGround ={
initGrid : function(N) {
this.N=N;
this.grid = new Array(N);
for (var i = 0; i < N; i++) {
this.grid[i] = new Array(N);
for (var j = 0; j < N; j++) {
this.grid[i][j] = false;
}
}
return true;
}
};
var PlayGround_property = {
N:{
value: 100,
writable:true
},
grid:{
value:null,
writable:true
}
}
var board= Object.create(PlayGround, PlayGround_property);
It works as I want: the object board contains the object grid, and now I can use the set and get keyword to define the behaviour of the = and () operator.
Anyway I have read around the web that the
this
keyword in Javascript is not safe and I want to be sure that it is referring always to the board object and not to the global window object. Is there a way or I am overthinking?
Other question, are there other ways to write object with a constructor (and maybe other members) in Javascript?
I want to be sure that [this] is referring always to the board object
A function's this is set either by how you call the function, or bind. So just make sure you call methods the right way. If you always call functions as methods of board, then this within the methods will always reference board.
If you are only going to have one instance of board, there doesn't seem much point in using a constructor. If you have multiple instances of board, then you want this to reference the particular instance that called the method so you don't want to fix this using bind.
Crockford just doesn't like the use of new, so encouraged Object.create, it fits his idea of how inheritance should work.
Your pattern could be rewritten to use a constructor something like:
function PlayGround (N) {
this.N = N;
this.grid = []; // Use array literal, it's less to type
for (var i = 0; i < N; i++) {
this.grid[i] = [];
for (var j = 0; j < N; j++) {
this.grid[i][j] = false; // Not sure why you bother with this
}
}
}
var board = new Playground(100);
I'm not exactly sure what you're doing, but that should be close. Note that javascipt is loosely typed, so only initialise variables and properties if you have something useful to assign. Variables are created with a value of undefined, Array properties are only created if you actually assign something to them, creating an array with length N does not create any indexes, e.g.
var arr = new Array(10);
console.log(arr.length); // 10
console.log(arr.hasOwnProperty(0)); // false

How do i create variable names using contents of an array using javascript

i have created an array,
var myBuildingName=['A1','A2','A3','A4'];
where A1,A2,A3 and A4 are the names obtained through user input.
i now want to create arrays that have names A1,A2,A3 and A4.
i have tried using
for(var i=0;i<myBuildingName.length;i++)
{
var myBuildingName[i]=[];
}
but it does not work...
please help.
You create a master parent object and use the array values as keys into the object where you can store an array for each.
var myBuildingName=['A1','A2','A3','A4'];
var master = {};
for (var i = 0; i < myBuildingName.length; i++) {
master[myBuildingName[i]] = [];
}
Then, you can access the data like:
var a1Array = master['A1'];
or
var firstA1Item = master['A1'][0];
If you actually wanto create variables with those names (which I won't recommend), you'd have to eval() them. So:
for(var i=0;i<myBuildingName.length;i++)
{
eval("var " + myBuildingName[i] + " = [] "); // This creates Array variables called A1, A2 etc.
}
Again, the above method is NOT recommended. You should assign the names as keys to an object literal, like:
var myStuff = {};
for(var i=0;i<myBuildingName.length;i++)
{
var myStuff[myBuildingName[i]] = [];
}
You can't access the local variable object (except in global code), so you can't add properties other than by variable declaration. For global code in the global context you could do:
var global = this;
for ( ...) {
global[myBuildingName[i]] = []
}
but you can't do that for function code in function context. See jfriend00's answer.
Here's a demo
var myBuildingName = ['A1', 'A2', 'A3', 'A4'];
function arrayFromNames(arr) {
var store = {}; //storage for the arrays
for (var i = 0; i < arr.length; i++) { //for each in the passed names
store[arr[i]] = []; //add to the storage an array with the corresponding name
}
return store; //return the storage
}
var nameArrays = arrayFromNames(myBuildingName); //build using your array
console.log(nameArrays);​
//you now have:
//nameArrays.A1, nameArrays.A2,...
//or
//nameArrays['A1'], nameArrays['A2'],...
You have received a lot of great answers, if one of them serves your need, you should accept that answer. The fact that this is still open makes us think no-one has quite answered your question the way you had hoped.
If that is the case, I can only assume that you wanted to use those variables in a global scope.
var myBuildingName=['A1','A2','A3','A4'];
for (var i = 0; i < myBuildingName.length; i++) {
window[myBuildingName[i]] = [];
}
Now you can access your variables 'normally'.
A1.push('test');
Note: this is horrible practice, since you should never pollute the global space.

Three map implementations in javascript. Which one is better?

I wrote a simple map implementation for some task. Then, out of curiosity, I wrote two more. I like map1 but the code is kinda hard to read. If somebody is interested, I'd appreciate a simple code review.
Which one is better? Do you know some other way to implement this in javascript?
var map = function(arr, func) {
var newarr = [];
for (var i = 0; i < arr.length; i++) {
newarr[i] = func(arr[i]);
}
return newarr;
};
var map1 = function(arr, func) {
if (arr.length === 0) return [];
return [func(arr[0])].concat(funcmap(arr.slice(1), func));
};
var map2 = function(arr, func) {
var iter = function(result, i) {
if (i === arr.length) return result;
result.push(func(arr[i]));
return iter(result, i+1);
};
return iter([], 0);
};
Thanks!
EDIT
I am thinking about such function in general.
For example, right now I am going to use it to iterate like this:
map(['class1', 'class2', 'class3'], function(cls) {
el.removeClass(cls);
});
or
ids = map(elements, extract_id);
/* elements is a collection of html elements,
extract_id is a func that extracts id from innerHTML */
What about the map implementation used natively on Firefox and SpiderMonkey, I think it's very straight forward:
if (!Array.prototype.map) {
Array.prototype.map = function(fun /*, thisp*/) {
var len = this.length >>> 0; // make sure length is a positive number
if (typeof fun != "function") // make sure the first argument is a function
throw new TypeError();
var res = new Array(len); // initialize the resulting array
var thisp = arguments[1]; // an optional 'context' argument
for (var i = 0; i < len; i++) {
if (i in this)
res[i] = fun.call(thisp, this[i], i, this); // fill the resulting array
}
return res;
};
}
If you don't want to extend the Array.prototype, declare it as a normal function expression.
As a reference, map is implemented as following in jQuery
map: function( elems, callback ) {
var ret = [];
// Go through the array, translating each of the items to their
// new value (or values).
for ( var i = 0, length = elems.length; i < length; i++ ) {
var value = callback( elems[ i ], i );
if ( value != null )
ret[ ret.length ] = value;
}
return ret.concat.apply( [], ret );
}
which seems most similar to your first implementation. I'd say the first one is preferred as it is the simplest to read and understand. But if performance is your concern, profile them.
I think that depends on what you want map to do when func might change the array. I would tend to err on the side of simplicity and sample length once.
You can always specify the output size as in
var map = function(arr, func) {
var n = arr.length & 0x7fffffff; // Make sure n is a non-neg integer
var newarr = new Array(n); // Preallocate array size
var USELESS = {};
for (var i = 0; i < n; ++i) {
newarr[i] = func.call(USELESS, arr[i]);
}
return newarr;
};
I used the func.call() form instead of just func(...) instead since I dislike calling user supplied code without specifying what 'this' is, but YMMV.
This first one is most appropriate. Recursing one level for every array item may make sense in a functional language, but in a procedural language without tail-call optimisation it's insane.
However, there is already a map function on Array: it is defined by ECMA-262 Fifth Edition and, as a built-in function, is going to be the optimal choice. Use that:
alert([1,2,3].map(function(n) { return n+3; })); // 4,5,6
The only problem is that Fifth Edition isn't supported by all current browsers: in particular, the Array extensions are not present in IE. But you can fix that with a little remedial work on the Array prototype:
if (!Array.prototype.map) {
Array.prototype.map= function(fn, that) {
var result= new Array(this.length);
for (var i= 0; i<this.length; i++)
if (i in this)
result[i]= fn.call(that, this[i], i, this);
return result;
};
}
This version, as per the ECMA standard, allows an optional object to be passed in to bind to this in the function call, and skips over any missing values (it's legal in JavaScript to have a list of length 3 where there is no second item).
There's something wrong in second method. 'funcmap' shouldn't be changed to 'map1'?
If so - this method loses, as concat() method is expensive - creates new array from given ones, so has to allocate extra memory and execute in O(array1.length + array2.length).
I like your first implementation best - it's definitely easiest to understand and seems quick in execution to me. No extra declaration (like in third way), extra function calls - just one for loop and array.length assignments.
I'd say the first one wins on simplicity (and immediate understandability); performance will be highly dependent on what the engine at hand optimizes, so you'd have to profile in the engines you want to support.

Categories

Resources