I need help with this JS callback function. I am trying to figure out how exactly callbacks work in JS.
--quick test code follows:
function debFilter(deb_array, fillCb){
var filt_darr = [];
for (var inx in deb_array) {
filt_darr.push(fillCb(deb_array[inx]));
}
return filt_darr;
}
console.log(debFilter(savedInp, function(x) { if (x%2 == 0) { return x;}} ));
Let's say my savedInp array contains [2,3,4,5,6,7,8,9] something like this. How do I make sure my callback returns only the even elements and not the odd ones? so my filt_darr would be [2,4,6...etc].
With the above test code I am getting [2,undefined,4,undefined,..etc]. I have tried with other similar conditions too with no avail. I just need to know how to tell JS not to 'push/return' something I dont need. Sorry if this is a beginner Q.
Thanks for the help.
Iterate the array and then push evens into a new array:
var a = [1,2,3,4,5];
function getEvens(originalArray){
var evens = [];
for(var i = 0; i < originalArray.length; ++i){
if(originalArray[i] % 2 === 0){
evens.push(originalArray[i]);
}
}
return evens;
}
As you probably noticed, you are collecting every return value into your result array and your callback returns undefined for every odd.
You could change your code to sth like
function debFilter(deb_array, fillCb){
'use strict';
var filt_darr = [],
len = deb_array.length;
for (var i = 0; i < len; i++) {
if (fillCb(deb_array[i])) {
filt_darr.push(deb_array[i]);
}
}
return filt_darr;
}
By the way, ES 5 supports Array.prototype.filter which might be what you are looking for. There is also a polyfill that you can take some inspiration from.
Related
In Ruby, there's a method called, Enumerable#cycle, which allows for repeated loops by x number of times in a collection. I'm looking for something similar in JavaScript but could not find an equivalent.
Does anyone know of a JavaScript equivalent to Ruby's, Enumerable#cycle?
Context: I am trying to loop over the same array in JavaScript -- twice. Once iteration reaches the end, I would like the iteration to start from the beginning of the array and eventually stop. The stopping part is not hard -- it's the cycling of the iteration that I'm trying to achieve in JavaScript. I've been able to do this in Ruby, however, with said method.
I think there is nothing inbuilt which is equivalent to this but if you need to you can follow this post for more detail:
Javascript call a function several times with the arguments.
Apart from the options provided there, you could also extend the Array.prototype to enable this method:
Array.prototype.cycle = function (n, callback) {
for (var i = 0; i < n; i++) {
this.forEach(callback);
}
}
and, could use this like following:
a = [1, 2, 3, 4]
a.cycle(2, function (i) { console.log(i); });
// this will print all the values two times
There is no JavaScript built in (or even proposed to my knowledge) that can do this. However, it's not too hard to accomplish yourself.
Let's assume for a minute that your talking about Arrays, and let's waive away discussion about modifying prototypes or not. The simple version of what you want could be:
Array.prototype.cycle = function(cycleCount, callback) {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback);
}
}
Let's assume you have an array of numbers. Then you could call this by doing:
myNumberArray.cycle(2, function(num, i) {
return num * 2;
});
We could even get fancy, and let you specify a different action for each cycle:
Array.prototype.cycle = function(cycleCount, callback) {
if(Object.prototype.toString.call( callback ) === '[object Array]') {
if(callback.length === cycleCount) {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback[i]);
}
} else {
// Uhoh, we don't have the right number of callbacks
throw new Error('If using multiple callbacks, the umber of callback\'s must match the number of cycles');
}
} else {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback);
}
}
}
There is more error checking you would need to do to make that robust, but you get the idea. :)
I'm sure I could eventually figure this out, but the documentation is a bit verbose and I think this ought to be a common question about asm.js.
Here goes:
Suppose that I have a function that looks like this:
function computeSquares() {
var i, array = [];
for(i = 0; i < 100; i++) {
array.push(i * i);
}
return array;
}
The above function computes the square of the integers from 0 to 99 and returns an array containing the results.
I would like to write a function like this in asm.js that returns an object containing the 100 square values. If I've read the documentation, I'm supposed to use the ArrayBuffer object, but I'm a bit confused about how to do it.
Please illuminate me by giving an example of how to code this with asm.js.
You can only return doubles, signed ints and voids from exported functions. If you want to return an array you'll have to write it into the heap.
The module would look like this:
function squaresModule(stdlib, foreign, heap) {
"use asm";
var imul = stdlib.Math.imul;
var array = new stdlib.Uint32Array(heap);
function compute( max ){
max = max|0; //max is an integer
var i = 0;
for( i = 0; (i|0) < (max|0); i = (i+1)|0 ) {
array[ i <<2>>2 ] = imul(i, i)|0;
}
return 0; //asm functions have to return a number
}
return {compute:compute};
}
.
Then use execute and log the array:
var array = Uint32Array( 100 );
var module = squareModule(
{Math:Math,Uint32Array:Uint32Array}, {}, array.buffer
);
module.compute(100);
console.log(array);
Instead of returning an array, I write the results in a convenient representation inside asm.js and then extract it with a wrapper function in JS that repeatedly calls into asm.js code to get the next value:
var result = [];
var i = 0;
while (true) {
i = return_next_array_value_from_asmjs();
if (i !== 0) {
result.push(i);
} else {
break;
}
}
The downside is that you need to reserve at least one value as a stop marker. I have not tested the performance because I couldn't get any other method to work.
My values naturally come in this form:
[1,2,3,4,5,6,7,8,9]
I am developing against a server api which requires an input parameter like:
[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9]
Is there a faster or more js-style way to do than a simple for loop?
var f = function(values) {
var newList = [];
var i;
for (i = 0; i < values.length; i++) {
newList.push(values[i]);
newList.push(values[i]);
}
return newList;
}
You could avoid a .push() call by combining them since .push() is variadic.
newList.push(values[i], values[i]);
Other than that, I doubt you'll get much quicker.
You can use each function.
this will reduce your step.
var list=[1,2,3,4,5,6,7,8,9]
var newlist=[];
$.each(list,function(index,data){newlist.push(data);newlist.push(data)})
hope this helps.
May be assignment is faster...
L2 = [];
for (var i=L1.lenght*2; i-->0;) {
L2[i>>1] = L1[i];
}
but this kind of micro-optimization really needs to be profiled on the specific implementations (and I wouldn't be surprised in big differences between different Javascript engines).
I'd keep the most readable way unless this is a key issue (and if it's a key issue they probably Javascript is the wrong tool).
Try: [].concat.call([1,2,3,4,5,6,7,8,9],[1,2,3,4,5,6,7,8,9]).sort();
or more generic:
(function(){
return this.concat(this).sort(function(a,b){return a-b;});}
).call([1,2,10,20,30,40,50,60,70,80,9]);
or just a function:
function(v) {
var i = v.length, nw = [];
while (i--) { nw.push(v[i],v[i]); }
return nw.reverse();
}
or using map
var nw = ([1,2,3,4,5].map(function(a){this.push(a,a)},nw=[]),nw);
I suspect the function is the most efficient.
A small two hours ago I started: Nested HandlebarsJS #each helpers with EmberJS not working
Shortly after I figured an acceptable temporary solution myself, question is still unaswered. My problems didn't stop there though.
I am now trying to make a custom helper which will loop through an array of objects, but exclude the first index - pretty much: for(i = 1; i < length; i++) {}. I've read on websites you have to get the length of your context and pass it to options - considering your function looks like: forLoop(context, options).
However, context is a string rather than an actual object. When you do a .length, you will get the length of the string, rather than the size of the array. When I pass that to options, nothing happens - not too mention browser freezes.
I then first tried to do a getPath before passing it to options, this returns an empty string.
What am I supposed to do instead, I made the for-loop code before for just HandlebarsJS and that worked, but EmberJS doesn't seem to take it, why?
EDIT: I pretty much also followed: http://handlebarsjs.com/block_helpers.html -> Simple Iterators
I solved this myself after trying for a long time.
The HandlebarsJS method (as described on the site) is no longer valid for EmberJS, it's now as follows:
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
options(object[i]);
}
}
Heck, you could even extend the for-loop to include an index-value!
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
object[i].index = i;
options(object[i]);
}
}
This is a working for-loop with variable start index. You use it in your templates like so:
{{#for anArray start=1}}
<p>Item #{{unbound index}}</p>
{{/for}}
Here is how I did it (and it works !!!)
First,
i had in my model a 'preview' property/function, that just return the arrayController in an array :
objectToLoop = Ember.Object.extend({
...
arrayController: [],
preview: function() {
return this.get('arrayController').toArray();
}.property('arrayController.#each'),
...
});
Then, I add a new Handlebars helper :
Handlebars.registerHelper("for", function forLoop(arrayToLoop, options) {
var data = Ember.Handlebars.get(this, arrayToLoop, options.fn);
if (data.length == 0) {
return 'Chargement...';
}
filtered = data.slice(options.hash.start || 0, options.hash.end || data.length);
var ret = "";
for(var i=0; i< filtered.length; i++) {
ret = ret + options.fn(filtered[i]);
}
return ret;
});
And thanks to all this magic, I can then call it in my view :
<script type="text/x-handlebars">
<ul>
{{#bind objectToLoop.preview}}
{{#for this end=4}}
<li>{{{someProperty}}}</li>
{{/for}}
{{/bind}}
</ul>
</script>
And that's it.
I know it is not optimal, so whoever have an idea on how to improve it, PLEASE, make me know :)
Hello I'm working on a problem that requires me to change an set array of numbers into an array that returns the original numbers as a function. So we get a return of a2 instead of a[2].
I dont want the answer I just need a hint. I know i can loop through the array and use .pop() to get the last value of the array, but then I dont know how to convert it to a function from there. any hints?
var numToFun = [1, 2, 3];
var numToFunLength = numToFun.length;
for (var i = 0; i < numToFunLength; i++) {
(function(num){
numToFun.unshift(function() {
return num;
});
}(numToFun.pop()))
}
DEMO
basically it pops out a number from the last, builds a function with that number returned, and put back into the first of the array. after one full cycle, all of them are functions.
here's the catch: how this works, it's up to you to research
why the loop does not look like the straightforward pop-unshift:
for (var i = 0; i < numToFunLength; i++) {
numToFun.unshift(function() { //put into first a function
return numToFun.pop() //that returns a number
});
}
and why i did this: (HINT: performance)
var numToFunLength = numToFun.length;
There's three important steps here:
Extract the number value from the array. Within a loop with an iterator of i, it might look like this:
var num = numArray[i];
This is important, because i will not retain its value that it had when you created the new function - it'll end up with the last value it had, once the for loop is finished. The function itself might look like this:
function() { return num; }
There's no reference to i any more, which is important - to understand better, read about closures. The final step would be to add the new function to the array of functions that you want.
...and you're done!
EDIT: See other's answers for good explanations of how to do this right, I will fix mine also though
As others have pointed out, one of the tricky things in javascript that many struggle with (myself included, obviously) is that scoping variables in javascript is dissimilar to many other languages; scopes are almost purely defined by functions, not the {} blocks of, for example, a for loop, as java/C would be.
So, below you can see (and in other answers here) a scoping function can aid with such a problem.
var numArray = [12, 33, 55];
var funcArray = [];
var numArrLength = numArray.length; // Don't do this in for loop to avoid the check multiple times
for(var j=0; j < numArrLength; j++) {
var scopeMe = function() {
var numToReturn = numArray[j];
console.log('now loading... ' + numToReturn);
var newFunc = function() {
return numToReturn;
};
return newFunc;
}();
funcArray.push(scopeMe);
};
console.log('now me');
console.log(funcArray);
console.log(funcArray[0]());
console.log(funcArray[1]());
console.log(funcArray[2]());
console.log(funcArray[1]()); // To ensure it's repeatable
EDIT my old bad answer below
What you'll want to do is something like
var funcArray = [];
for(...) {
var newFunc = function() {
return numArray.pop();
}
funcArray.push(newFunc);
}
The key here is that functions in javascript can be named variables, and passed around as such :)