about optimizing for-in statement - javascript

I read an article named Optimization killers, and in 5.2.3. The object contains enumerable array indices, It says :
Workaround: Always use Object.keys and iterate over the array with for loop. If you truly need all properties from entire prototype chain, make an isolated helper function:
function inheritedKeys(obj) {
var ret = [];
for(var key in obj) {
ret.push(key);
}
return ret;
}
I don't understand what it means.
In the above code, there is still a for...in, so function inheritedKeys can't be optimized, how can it be an isolated helper function?

That's just an example on how to get keys from an object doing it with the for in loop.
He actually tells you that in order to make it faster you should use Object.keys when you want to get keys of an object.
Here's the test performance.
http://jsperf.com/forintest
So DON'T use this to retrieve object keys
function inheritedKeys(obj) {
var ret = [];
for(var key in obj) {
ret.push(key);
}
return ret;
}
var myobject= {"1":"a","2":"b"};
var calculation = inheritedKeys(myobject);
Use this instead it's more clean simple to read and faster
var myobject= {"1":"a","2":"b"};
var calculation = Object.keys(myobject);
Here's a test comparing for in using with array and a normal for loop.
http://jsperf.com/forinarray
You can see that the for loop is way faster.
DON'T use this
function iteratesOverArray() {
var arr = [1, 2, 3];
var newArr = [];
for (var index in arr) {
newArr.push(index);
}
return newArr;
}
var arr = iteratesOverArray();
Use this instead
function iteratesOverArray() {
var arr = [1, 2, 3];
var newArr = [];
for (var i=0,l=arr.length-1;i<=l;i++) {
newArr.push(i);
}
return newArr;
}
var arr = iteratesOverArray();

Related

JS How to make a new method to an Array using prototype but with a function that takes no parameters

I want to extend the Array with a new method called square() which returns a new array with all the numbers squared. I tried making it but I can't figure out a way in which the function does not take any parameters like the default JS Array methods. For example array.reverse() returns the array reversed it doesn't take the array as the parameter, like this: array.reverse(array)
This is my code:
Array.prototype.square = function(Array){
let a = []
for (let num of Array){
a.push(num**2)
}
return a
}
You can use the this keyword inside of your function and it will refer to the array calling it.
Array.prototype.square = function() {
return this.map(number => number ** 2)
}
let test = [1, 2, 3]
console.log(test.square())
You were on the right track, it can be easily done like this:
Array.prototype.square = function () {
return this.map((number) => number * number)
}
let a = [1, 2]; // sample array
console.log(a.square()); // prints [1, 4]
I have used map, which makes the process extremely easy. Refer to this for more information: Array Map Function
for the record...
(the name of this kind of added method is called a wrapper)
/* --- Array.square wrapper--- */
if (!Array.prototype.square) // check that the square method does not already exist
{
Array.prototype.square = function(){ return this.map(x=>x**2) }
}
let arr1 = [1,2,3,5,7]
, arr2 = arr1.square()
;
console.log('arr1 ->', JSON.stringify( arr1 ))
console.log('arr2 ->', JSON.stringify( arr2 ))
When you add methods to a prototype the object/array will always be the this context. So you can simply loop over this.
(Aside: it's often good to check that the method doesn't already exist on the prototype which is why I included that code too.)
if (!('square' in Array.prototype)) {
Array.prototype.square = function() {
const arr = [];
for (let i = 0; i < this.length; i++) {
arr.push(this[i] ** 2);
}
return arr;
}
}
console.log([1, 2, 3].square());
Or, more simply, use map to return a new array.
if (!('square' in Array.prototype)) {
Array.prototype.square = function() {
return this.map(el => el ** 2);
}
}
console.log([1, 2, 3].square());

Student trying to understand callback functions

Hi I'm trying to learn how to implement callback functions. My teacher has helped me out multiple times but I still can't pass data through the following equation below. I'm trying to get certain elements of array to get pushed into a new function if only they pass a test within the function. Please have a look and thank you for your input. An explanation as to why I get an empty array and resources to further my understanding would be appreciated.
// EACH DEFINITION
function each (collection, callback) {
for(var i = 0; i < collection.length; i ++){
callback(collection[i]);
}
}
// VARIABLE DECLARATION
var myArray = [1,2,3,4,5,6];
var isEven = function (num) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
test(item);
});
if(test(array)){
arr.push(array);
}
return arr;
}
// IMPLEMENT INVOCATION
implement(myArray, isEven);
You are building arr outside the each() loop.
I would think your code would be like this:
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
if(test(item)) {
arr.push(item);
}
});
return arr;
}
Though in this case there is no reason for your implement() filtering function at all, since javascript Array prototype already has a filter method. You could simplify your call to this:
var filteredArray = myArray.filter(isEven);
Though you might also then want to change your isEven definition to be more correct as:
var isEven = function (num, index, array) {
In your case you don't need to work with the last two parameters.
// EACH DEFINITION
function each (collection, callback, results) {
for(var i = 0; i < collection.length; i ++){
callback(collection[i]);
}
console.log(results);
}
// VARIABLE DECLARATION
var myArray = [1,2,3,4,5,6];
var isEven = function (num, array) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
function filter (item) {
if (test(item)) {
arr.push(item);
}
}
each(array, filter, arr);
// If you return arr here, it will still be empty. You must pass it to functions it is being operated on.
}
// IMPLEMENT INVOCATION
implement(myArray, isEven);
Not only are you trying to push to arr outside of your loop, but you're trying to return arr before it has gained any values.
Two points:
First, your implementation of callback functions is correct. As far as the concept of callbacks goes, you are calling and passing the functions correctly.
However, your implement() function probably has a bug. You are not pushing to arr until after each() has already been called:
function implement(array, test) { // array = myArray, test = isEven
var arr = [];
each(array, function(item) {
result = test(item);
});
// This block should be in the loop itself
// It should also refer to item, not array
if (test(array)) {
arr.push(array);
}
return arr;
}
Try this fix based on the code you provided:
// EACH DEFINITION
function each(collection, callback) {
for (var i = 0; i < collection.length; i++) {
callback(collection[i]);
}
}
// VARIABLE DECLARATION
var myArray = [1, 2, 3, 4, 5, 6];
var isEven = function(num) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test) { // array = myArray, test = isEven
var arr = [];
each(array, function(item) {
if (test(item)) {
arr.push(item)
}
});
if (test(array)) {
arr.push(array);
}
return arr;
}
// IMPLEMENT INVOCATION
var result = implement(myArray, isEven);
console.log(result); // For snippet results
Your callback, as you defined it, is
function(item){
test(item);
}
this will only call test on each item and that's it. Since you want to take it further and add item to arr if test returns true, you should put that checking code inside the callback as well, making it
function(item){
if (test(item)) {
arr.push(item);
}
}
so that this function will be called for each of the item.
Also, this part
if(test(array)){
arr.push(array);
}
is incorrect because you are passing a whole array into isEven when isEven is expecting a number. test(array) will always return false; that's why your arr is empty.
Modifying your code to work as you wanted, it would be
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
if (test(item)) {
arr.push(item);
}
});
return arr;
}
Resources wise, there are callbacks tutorial widely available online, as well as best practices. You can easily find one that suits you best by googling.
It looks to me like the entire issue here is in the implementation section you denote. All of the other code looks adequate.
each(array, function(item){
test(item);
});
Alright, first let's examine this piece of code. You are making a call to your each function, which will use the callback anonymous function defined here as shown.
However, if you were to look at the each function itself, there is no return (which means it returns undefined by default). There is also no modification being done in each. As a result, this set of code has no effect on the execution of the code, and from certain advanced compilation technique may actually be removed by the V8 engine in chrome if that was being used.
This means the only aspect of your code which is executing is
var arr = [];
if(test(array)){
arr.push(array);
}
return arr;
At this point, test is still the isEven function, so you are basically asking this
if(array % 2 === 0) arr.push(array);
Arrays in JavaScript behave interestingly when used in conditional statements, and in this situation the array essentially has toString called on it (more in depth here: https://stackoverflow.com/a/10556035/1026459 , but basically when you have object === number then it will attempt to use toPrimitive on the object which results in a string), which makes it
if("1,2,3" % 2 === 0)
which is false. As a result arr is unchanged, and returned in its original state of [].

Populating JavaScript Object

We have an empty object:
var obj = {};
I would like to make a for loop which with each iteration adds a new obj = {value: i, next: i+1}
Simply use an array of objects and for every iteration push this values on it:
var obj=[];
for(var i=1;i<10;i++){
obj.push({value: i, next: i+1});
}
This is a DEMO Fiddle.
For each iteration give the obj.value and the obj.next, take a look at JavaScript Object Properties for futher information.
Not that sure what you mean but what about this
var obj = [];
function Obj(i){
this.value = i;
this.next = i+1;
}
for (var i= 0;i<10;i++){
obj.push(new Obj(i));
}
Instead of an object of objects an array of them

Merge values of multiple arrays in object with jQuery or underscore.js

I want to merge values of multiple arrays in one object to one array.
For instance:
Object:
- alpha: Array[3]
0: "vatG4d6mcjKbpfuAm"
1: "xkQrKEsfwuYPkDcdz"
2: "GDg9chZnDGrbLXWGS"
- bravo: Array[1]
0: "53LEcQ5MoYXFyvktf"
- …
The result should be:
["vatG4d6mcjKbpfuAm", "xkQrKEsfwuYPkDcdz", "GDg9chZnDGrbLXWGS", "53LEcQ5MoYXFyvktf"]
I did this with a simple for loop iterating over the elements, but I am concerned about the performance. Is this possible with a simple jQuery or underscore.js function?
Any help would be greatly appreciated.
There's no need to use a library for this.
For two arrays use concat:
var arr = obj.alpha.concat(obj.bravo);
For more than two arrays use a loop:
Either with concat again
var arr = [];
for (var k in obj) {
arr = arr.concat(obj[k]);
}
Or using the push.apply method
var arr = [];
for (var k in obj) {
arr.push.apply(arr, obj[k]);
}
DEMO
Make a function using this information so you don't need to repeat code:
function mergeObjectArrays(obj) {
var arr = [];
for (var k in obj) {
arr.push.apply(arr, obj[k]);
}
return arr;
}
var arr = mergeObjectArrays(obj);
with jquery you can use merge
var newArray = $.merge(array1, array2);
with underscore you can use union
var newArray = _.union(array1, array2);
You can concat the arrays using pure javascript like this:
var obj =
{
alpha: ["vatG4d6mcjKbpfuAm", "xkQrKEsfwuYPkDcdz", "GDg9chZnDGrbLXWGS"],
bravo: ["53LEcQ5MoYXFyvktf"]
};
var obj.charlie = obj.alpha.concat(obj.bravo);
// obj.charlie = ["vatG4d6mcjKbpfuAm", "xkQrKEsfwuYPkDcdz", "GDg9chZnDGrbLXWGS", "53LEcQ5MoYXFyvktf"]

How to convert array into object?

I have this array, var arr = [0, 1, 2]
and I would like to convert it into an object like this,
Object{
data: [0, 1, 2]
}
How would I get the desired output using a function perhaps? Thanks.
Just create an object and assign the array to one it it's properties:
var arr = [0, 1, 2];
var obj = {
data : arr
};
Or if you have an existing object, you can add the array by name:
obj['data'] = arr;
Or dot notation:
obj.data = arr;
You should be aware that these are all copying the array by reference, so any updates you make to the arr variable will update obj.data as well. If you want to copy by value, you could do something like:
var obj = {
data: arr.slice(0)
};
See this JSFiddle for an example of copying by reference versus copying by value. You could read the answer to this question for more information about copying by value vs copying by reference.
You can do this very easily like this var obj = {data:arr}; However I think you should consider what purpose you are using the object for. An array is technically already a javascript object so you may not even need to do this
It's quite easy you just need a factory for it.
function arrayToObjectTransformationFactory($array, $transformationTransportProtocol){
return function($array){
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
};
}
$array.forEach($transformationTransportProtocol)
return { "data": $array };
}($array);
}
arrayToObjectTransformationFactory([0, 1, 2], function($element, $index, $array){
var quux = [];
quux.push($array[$index]);
});
Should work cross browser and with jQuery too.

Categories