In recent interview, interviewer has asked can you write polyfill for push() method in javascript.
any one know how to do this .?
push() adds one or more elements at the end of array and returns new length of array. You can use array's length property to add element at the end of it.
if (!Array.prototype.push) {
// Check if not already supported, then only add. No need to check this when you want to Override the method
// Add method to prototype of array, so that can be directly called on array
Array.prototype.push = function() {
// Use loop for multiple/any no. of elements
for (var i = 0; i < arguments.length; i++) {
this[this.length] = arguments[i];
}
// Return new length of the array
return this.length;
};
}
if (!Array.prototype.push) {
Array.prototype.push = function () {
for (var i = 0, len = arguments.length; i < len; i++) {
this[this.length] = arguments[i];
if (Object.prototype.toString.call(this).slice(8, -1).toLowerCase() === 'object') {
this.length += 1;
}
}
return this.length;
};
}
Related
I have an array of 100 objects with different properties in each object. I am trying to do a for loop through the array to get 1 particular property from each object and push it to a new array. I've tried:
for (var item in response.data) {
main.allUsers.push(item);
}
And when I console.log(main.allUsers); I get an array that looks like ["0","1", "2", "3", "4"...] .
When looping through an object properties, the left-side of the for...in loop is a string that represents the current object's property name. So, you must use the notation object['property'] to get the correspondent value of that property. You should be using:
main.allUsers.push(response.data[item]);
Although, it seems your response.data is an Array, not an object, so, you shouldn't be using for...in at all, since it was designed to loop through object properties.
When looping through an Array, you should be using the regular for loop, or you can use the Array.prototype.forEach loop, which will iterate similar to the way your trying with for...in. When ES6 be fully supported, you'll be able to use the for...of loop, that's similar to what you're trying:
for (var i = 0; i < response.data.length; i++) {
var item = response.data[i];
main.allUsers.push(item);
}
// or
response.data.forEach(function(item, i) {
main.allUsers.push(item);
}
// and in the future (it already works in Firefox, if you wanna give a try)
for (var item of response.data) {
main.allUsers.push(item);
}
Update
Answering to your comment, you could be using:
response.data.forEach(function(item) {
main.allUsers.push(item.DisplayName);
});
// or
for (var i = 0; i < response.data.length; i++) {
main.allUsers.push(response.data[i].DisplayName);
}
// or if you don't have any items inside main.allUsers yet
main.allUsers = response.data.map(function(item) { return item.DisplayName; });
Using javascript you could also do the following.. Jsfiddle
var arrayOfObjects = [
{name: "myName1",
age: 12
},
{surname: "mySurname2",
age: 26
}
//98 more...
];
var myData = [];
for(var i = 0; i < arrayOfObjects.length; i++){ //iterate array of objects
for(var key in arrayOfObjects[i]){ //iterate each object key
if(arrayOfObjects[i].hasOwnProperty(key) && key == "age"){
//make sure its the key you want
myData.push(arrayOfObjects[i].age);
}
}
}
console.log(myData);
To get each object in an array, you have to use
for(var i=0; i < response.data.length; i++){
var obj = response.data[i];
}
And now to get each property of object,
for(var i=0; i < response.data.length; i++){
var obj = response.data[i];
for (property in obj){
console.log(property);
}
}
Don't use for..in with arrays https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/for...in#Array_iteration_and_for...in. Use forEach, or standard for, or map. Like:
var _len = response.data.length;
for (var i = 0; i < _len; i++) {
main.allUsers.push(response.data[i]);
}
I am using this snippet to extend Array's functionality with getUnique function:
Array.prototype.getUnique = function() {
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
The slight drawback is that the attribute getUnique is printed together with array elements if I console.log an array:
["126", "125", getUnique: function]
It is slightly disturbing even if I know that getUnique is not considered as an array element. This happens in Chrome. Not in Firefox as far as I know. Is there a way to prevent it?
Use Object.defineProperty and enumerable:
Object.defineProperty(Array.prototype, 'getUnique',
{ enumerable: false
, configurable: true
, writable: true
, value: function ()
{ var u = {};
var a = [];
for (var i = 0, l = this.length; i < l; ++i)
{ if (u.hasOwnProperty(this[i])) continue;
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
});
By default, a property is enumerable (even if it's not a direct property of an instance), which means that it is visible through any for-in loop (or Object.keys) of the array. Chrome does something similar to a for-in loop on an array, which is why it is represented as it is.
Note that this function only works in (relatively) modernish browsers which support ES5, which means that IE < 9, some older Android browsers and other mobile devices may not be able to use this code. This is one of the reasons why some people recommend against extending the prototypes of native constructors, as this issue can break code that isn't well constructed against these issues. What people who believe this usually recommend is to not place the function on the prototype:
function getUnique(arr)
{ var u = {};
var a = [];
for (var i = 0, l = array.length; i < l; ++i)
{ if (u.hasOwnProperty(arr[i])) continue;
a.push(arr[i]);
u[arr[i]] = 1;
}
return a;
}
I'd also like to point out that only one object will be ever printed by the getUnique function, as it is technically incorrect in its implementation. While rather similar, objects are not dictionaries and can only have string keys, which means that any object (no matter the contents) will have a string value of '[object Object]', which means that when your function encounters another object (even if it has different values), it will not be added to the returned array. While inefficient, the only way I can think of is to iterate through the array each time:
function getUnique(arg)
{ 'use strict';
var O = Object(arg);
var len = O.length >>> 0;
var A = [];
var indexOf = function (arg, searchElement)
{ for (var i = 0, l = arg.length; i < l; ++i) if (arg[i] === searchElement) return i;
return -1;
};
for (var k = 0; k < len; ++k)
{ var elementK = O[k];
var kPresent = k in O;
if (!kPresent || indexOf(A, elementK) !== -1) continue;
A[A.length - 1] = elementK;
}
return array;
}
I know IE8 and earlier doesn't have an indexOf function. I'm defining it as follows:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) { return i; }
}
return -1;
}
}
I can correctly get the index of values in an array, but the function is being added to the end of my arrays when using IE8 and earlier. Therefore, I'm getting things like:
obj.obj2[0] = 'data'
obj.obj2[1] = 'other data'
obj.obj2['indexOf'] = [definition of indexOf function]
Not surprisingly, this is breaking everything else on the site. Problem isn't happening in IE10 or 9. Any and all help is appreciated.
It is added to the prototype, so everytime you treat your array like an object (for..in loop is one example), it will show up. It does not show up in other browsers because they already have the indexOf method by default, so you're not modifying the prototype.
You can use obj.hasOwnProperty(propertyName) to test whether a property is defined directly on your object (in this case, your array, which is an object basically) or somewhere else in the prototype chain.
Sounds like you might be doing something wrong when iterating through your arrays. I ran the following in IE8 and didn't get the behavior you mentioned:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) { return i + " used prototype"; }
}
return -1;
}
}
var myCars=new Array("Saab","Volvo","BMW");
document.write(myCars.indexOf("Volvo") + "<br/><br/>");
for (i = 0; i < myCars.length; i++)
document.write(i + ": " + myCars[i] + "<br/>");
output:
1 used prototype
0: Saab
1: Volvo
2: BMW
In the case when we use Array.prototype.someFunction,
to filter truly array's elements in IE 8, we can use:
for (var i = 0, len = myArray.length; i < len; i++) {
if (typeof myArray[i] === "function") {break;}
// some code for myArray trully elements
}
IE<9 doesn't have an .indexOf() function for Array, to define the exact spec version, run this before trying to use it:
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
Reference
I currently have an array data structure that I iterate over like this, calling foo on each unique pair of elements.
for(var i = 0; i < arr.length; i++) {
for(var j = i + 1; j < arr.length; j++) {
foo(arr[i], arr[j]);
}
}
However, I've realized that I'd rather use an object instead of an array, since I can then add and remove elements by name very easily.
However, I can't see an obvious way to iterate over such an object. The closest I can get is:
for(i in obj) {
for(j in obj) {
foo(obj[i], obj[j]);
}
}
Obviously, this will do each pair twice, and even produce a pair of identical elements. Is there an easy way to iterate over an object in the same way as I do in the array in my first code sample?
Update:
Performance testing the solutions on jsperf.
My solution that was at first written as a comment:
Add an if (i < j) condition in the inner loop. It might not be the best solution, but it would work as long as the foo function does the same thing for foo(2, 10) and foo(10, 2):
for(i in obj) {
for(j in obj) {
if (i < j) {
foo(obj[i], obj[j]);
}
}
}
Assuming I understand your question... maybe check to see if the value has already been visited by the outer loop?
var visited = {}
for(i in obj) {
visited[i] = true;
for(j in obj) {
if(j in visited){ continue; }
foo(obj[i], obj[j]);
}
}
Use Object.keys() to get the list of keys out as an array:
keys = Object.keys();
for(i=0;i<keys.length;i++) {
for(j=i+1;j<keys.length;j++) {
foo(obj[keys[i]], obj[keys[j]]);
}
}
Maybe You can try unset used objects:
for(i in obj) {
var a = obj[i];
delete obj[i];
for(j in obj) {
foo(a, obj[j]);
}
}
http://jsfiddle.net/bXcvb/
If you need to original obj in tact see: How do I correctly clone a JavaScript object?
You can push the object keys into an array:
var obj_keys = [];
for (i in obj) {
obj_keys.push(i);
}
for(i = 0; i < obj_keys.length; ++i) {
for(j = i + 1; j < obj_keys.length; ++j) {
foo(obj[obj_keys[i]], obj[obj_keys[j]]);
}
}
I would like to extend the Javascript built-in Array object by addind a new method: searchByRegexp
Basically the method will get a regexp as input and will return:
_ a string representing the element of the array that matches the regexp (if more than one match, the first one will be returned)
_ an empty string if none of the elements matches the regular expression.
Quick and dirty (fiddle for your fiddling pleasure):
Array.prototype.searchByRegexp = function (rx) {
for(var i = 0, ln = this.length; i < ln; i++) {
// test item i
if(rx.test(this[i])) {
return this[i] + "";
}
}
// return an empty string if no matches are found
return "";
}
However, you may wish to implement more general methods instead...
Array.prototype.find = function(delegate) {
for(var i = 0, ln = this.length; i < ln; i++) {
if(delegate(this[i])){
return this[i];
}
}
return null;
}
Array.prototype.findAll = function(delegate) {
var results = [];
for(var i = 0, ln = this.length; i < ln; i++) {
if(delegate(this[i])){
results.push(this[i]);
}
}
return results ;
}
Array.prototype.each = function (delegate) {
for (var i = 0, ln = this.length; i < ln; i++) {
delegate(this[i], i);
}
}
... which could then perform regex comparison like so:
// test values
var sizes = ["Small", "Medium", "Large", "Extra-Large", "Extra-Extra-Large"];
// Print single value or blank
document.write(sizes.find(function(size){
return /large/i.test(size);
}) || "");
// horizontal rule to separate our results
document.write("<hr/>");
// Print all matches
sizes.findAll(function(size){
return /large/i.test(size);
}).each(function(size){
document.write(size + "<br/>");
});
As of today, using Google Chrome, the provided solution breaks the iteration over the array.
After Array.prototype.searchByRegexp = function ..., if you iterate with for (var k in arrayInstance), the value searchByRegexp will be in the keys, not only the real array keys.
To prevent that you should use Object.defineProperty(Array.prototype, ...
Object.defineProperty(Array.prototype, 'searchByRegexp', {
value: function (rx) {
for(var i = 0, ln = this.length; i < ln; i++) {
// test item i
if(rx.test(this[i])) {
return this[i] + "";
}
}
// return an empty string if no matches are found
return "";
},
enumerable: false
});