I'm looking for an alternative for the find() method of an array. I'm using it on Android Browser and Array.prototype.find() doesn't work there. Definition Array Support
var test= this.arrayOfValues.find(function (value) {
return (value.name === device.value)
});
If you do not care so much about programming your own, and if indexOf is somehow not usable, have a look at Underscore.js#find. As an alternative, as #NinaScholz recommended in the comments, use the Polyfill from mozilla.org:
if (!Array.prototype.find) {
Array.prototype.find = function(predicate) {
if (this === null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
return undefined;
};
}
Related
So, the JavaScript implementation that NetSuite employs for its server-side processing lacks the Array.find() method, as from what I found because it uses ECMAScript 5.1, and the method was defined in ES6 (TypeError: Cannot find function find in object), so that has limited some other options for handling this. So I wanted to define a replacement in my library file that would also be as efficient as possible (not naming them "find" to prevent overriding the default function in case my library is loaded into a browser). I have the following two versions:
Version #1
Array.prototype.altFind = function (func) {
if (func == null) { return null; }
for (var i = 0; i < this.length; i++) {
if (func(this[i])) {
return this[i];
}
}
return null;
}
Version #2
Object.defineProperty(Array.prototype, 'altFind',
{
value: function (predicate) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
if (predicate == null)) {
throw new TypeError('predicate is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var thisArg = arguments[1];
var k = 0;
while (k < len) {
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) { return kValue; }
k++;
}
return undefined;
}
, configurable: true
, writable: true
}
);
(NOTE: version #2 was found at https://netsuitehub.com/forums/topic/adding-modern-functionality-to-array-object-find-findindex-in-your-server-side-suitescripts/ to give them credit)
I'm not good at determining overall code efficiency, so would anyone be able to tell me which version would be the most ideal? Or if there's a way to make either of them more efficient?
I am getting the following error in IE 8
Object doesn't support this property or method
Helper.prototype.getUniqueArray = function(a) {
/*console.log(a);*/
return a.filter(function(elem, pos, self) {
if (elem === '') {
return false;
}
return self.indexOf(elem) === pos;
});
};
Please help me make this work in IE9 and lower.
Use pollyfill for .filter() as specified at the MDN docs:
Polyfill
filter() was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of filter() in ECMA-262 implementations which do not natively support it. This algorithm is exactly the one specified in ECMA-262, 5th edition, assuming that fn.call evaluates to the original value of Function.prototype.call(), and that Array.prototype.push() has its original value.
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun/*, thisArg*/) {
'use strict';
if (this === void 0 || this === null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function') {
throw new TypeError();
}
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];
// NOTE: Technically this should Object.defineProperty at
// the next index, as push can be affected by
// properties on Object.prototype and Array.prototype.
// But that method's new, and collisions should be
// rare, so use the more-compatible alternative.
if (fun.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
return res;
};
}
Looking at the MDN definition of Array.prototype.find(), I was wondering if there is another javascript method to return the first object from an array based on a predicate, that also works on older browsers.
I am aware of 3rd party libraries such as _underscore and Linq.JS that do this, but curious if there is a more "native" approach.
You can use MDN Polyfill which override this method in old browsers (Read the Tushar's comment).
if (!Array.prototype.find) {
Array.prototype.find = function(predicate) {
if (this === null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
return undefined;
};
}
Check this library: https://github.com/iabdelkareem/LINQ-To-JavaScript
It contains what you seek for [firstOrDefault] method for example:
var ar = [{name: "Ahmed", age: 18}, {name: "Mohamed", age:25}, {name:"Hossam", age:27}];
var firstMatch = ar.firstOrDefault(o=> o.age > 20); //Result {name: "Mohamed", age:25}
I am currently learning javascript from the definitive guide and many code examples use xyx.call(undefined,/*args*/) instead of just calling the function as xyz(/*args*/).
I know that if the executing context is set to undefined then the value of this will refer to the global object . I'am not able to figure out why this is done in most examples as they don't depends on values from the global object. Can anybody help me understand the difference.
Some implementation of Array.protype.reduce
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callbackfn, initialValue) {
"use strict";
var O = Object(this),
lenValue = O.length,
len = lenValue >>> 0,
k,
accumulator,
kPresent,
Pk,
kValue;
if (typeof callbackfn !== 'function') {
throw new TypeError();
}
if (len === 0 && initialValue === undefined) {
throw new TypeError();
}
k = 0;
if (initialValue !== undefined) {
accumulator = initialValue;
} else {
kPresent = false;
while(!kPresent && k < len) {
Pk = k.toString();
kPresent = O.hasOwnProperty(Pk);
if (kPresent) {
accumulator = O[Pk];
}
k += 1;
}
if (!kPresent) {
throw new TypeError();
}
}
while(k < len) {
Pk = k.toString();
kPresent = O.hasOwnProperty(Pk);
if (kPresent) {
kValue = O[Pk];
accumulator = callbackfn.call(undefined, accumulator, kValue, k, O);
}
k += 1;
}
return accumulator;
};
}
and some use :
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.reduce called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this), len = t.length >>> 0, k = 0, value;
if (arguments.length == 2) {
value = arguments[1];
} else {
while (k < len && ! k in t) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = t[k++];
}
for (; k < len; k++) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}
so in one method the callback function is called using call() and in other implementation its not
JavaScript is functional OO language.It have different pattern to invoke a function. xyz(/*args*/) and xyx.call(undefined,/*args*/) are two different kind of invocations.
xyz(/*args*/) - In this case this have window as its value.
xyx.call(undefined,/*args*/) - In this case this will be nothing but context whatever we pass in call like in this case undefined.
Only special thing of using xyx.call(undefined,/*args*/) is that you have reliability of choosing your context in your function call.When you are writing object oriented JavaScript at that time value of context matters a lot. That's why it is more explicit to use xyx.call(undefined,/*args*/) over xyz(/*args*/).
The reason your examples are using call for Array functions has to do with JavaScript's multiple (somewhat needless) array types.
As well as the standard object type that returns true on arr instanceof Array, there are also NodeLists returned from a document.querySelectorAll function, and other similar types. The important thing is, these other types don't have all of Array's helper functions (reduce, map, forEach).
However, they still have all that they technically need for those functions to work; and the .call method helps you to do that. So, let's say I have two collections.
var arr = [1,2,3];
var nodelist = document.querySelectorAll('.baby');
arr.map(function(val) { return val + 1; }); // Okay!
nodelist.map(function(val) { return val.innerHTML; }); // doesn't work
I can pull off the .map call on the nodelist with call, by giving it a different target-object.
Array.prototype.map.call(nodelist, function...etc)
// Technically, this works too; just grabbing the method from our arr
// instance, but it's cleaner to refer to the original
// type's method.
arr.map.call(nodelist, function...etc)
To explain the code samples you posted; those are "polyfills" - browsers should have a "reduce" function themselves, but older browsers might not. So, we create it ourselves to replicate the same functionality.
We have been using javascript "hashes" a lot lately, and we've been looking for a universal way to count the items contained in both arrays and hashes without having to "know" which we're dealing with except in the count method. As everyone knows .length is useless since it only returns the value of the highest index in the array. What we have below does not work because hashes test true for Array, but the length value returned is crap for hashes. We originally replaced .length all over our project with Object.keys().length, but this isn't supported in IE8 and lower.
This is such a stupid simple thing and we can't seem to get it working. Help me, Obi Wan. You're my only hope!
function isNullOrUndefined(aObject) {
"use strict";
return (typeof aObject === 'undefined' || aObject === null);
}
function count(aList) {
"use strict";
var lKey = null,
lResult = 0;
if (!isNullOrUndefined(aList)) {
if (aList.constructor == Array) {
lResult = aList.length;
} else if (!isNullOrUndefined(Object.keys)) {
lResult = Object.keys(aList).length;
} else {
for (lKey in aList) {
if (aList.hasOwnProperty(lKey)) {
lResult++;
}
}
}
}
return lResult;
}
Object.keys polyfill copied verbatim from the ES5-shim
// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14
if (!Object.keys) {
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = true,
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
for (var key in {"toString": null}) {
hasDontEnumBug = false;
}
Object.keys = function keys(object) {
if ((typeof object != "object" && typeof object != "function") || object === null) {
throw new TypeError("Object.keys called on a non-object");
}
var keys = [];
for (var name in object) {
if (owns(object, name)) {
keys.push(name);
}
}
if (hasDontEnumBug) {
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
var dontEnum = dontEnums[i];
if (owns(object, dontEnum)) {
keys.push(dontEnum);
}
}
}
return keys;
};
}
Despise the answer from Raynos that is completely valid please consider performance
This is how my hash object look like
function Hash(){
this.values = [];
this.keys = {};
}
Hash.prototype.set = function(key, val){
if(this.keys[key]){
this.values[this.keys[key]] = value
}else{
this.keys[key] = (this.values.push(val)-1)
}
}
Hash.prototype.length = function(){
return this.values.length
}
Why I do this is simple performance looping through an object to count the properties length will be really inefficient the solution above give you direct access all the time.