alternative for foreach and use regular for loop - javascript

This doesnt really work in IE
[].forEach.call(document.querySelectorAll('.some-class-selector'), function(arg) {
callSomeFucntion(arg)
});
because forEach doesn't work on IE. if I want to do this using for loop, how would I do this?

Need to add this for run forEach in IE
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7" />

What version of IE are you using? The Microsoft docs page for forEach lists the version that don't support it - mainly IE 6,7 and 8 or quirks mode (https://learn.microsoft.com/en-us/scripting/javascript/reference/foreach-method-array-javascript)
You can also use a polyfill if your browser won't support it MDN forEach:
forEach() was added to the ECMA-262 standard in the 5th edition; as
such it may not be present in other implementations of the standard.
You can work around this by inserting the following code at the
beginning of your scripts, allowing use of forEach() in
implementations that don't natively support it. This algorithm is
exactly the one specified in ECMA-262, 5th edition, assuming Object
and TypeError have their original values and that callback.call()
evaluates to the original value of Function.prototype.call().
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback/*, thisArg*/) {
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
// 1. Let O be the result of calling toObject() passing the
// |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get() internal
// method of O with the argument "length".
// 3. Let len be toUint32(lenValue).
var len = O.length >>> 0;
// 4. If isCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let
// T be undefined.
if (arguments.length > 1) {
T = arguments[1];
}
// 6. Let k be 0.
k = 0;
// 7. Repeat while k < len.
while (k < len) {
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator.
// b. Let kPresent be the result of calling the HasProperty
// internal method of O with argument Pk.
// This step can be combined with c.
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Call the Call internal method of callback with T as
// the this value and argument list containing kValue, k, and O.
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined.
};
}

Related

Meaning of (x => x) in JavaScript arrow function using array.every() method

looking for an explanation on this line of code. I understand arrow functions to a degree. The purpose of this code snippet/challenge is; "Given any number of parameters, return true if none of the arguments are falsy." I've seen the solution like this:
const nothingIsNothing = (...args) => args.every(x => x)
Examples of arguments and the expected results are:
nothingIsNothing(0, false, undefined, null) ➞ false
nothingIsNothing(33, "Hello", true, []) ➞ true
nothingIsNothing(true, false) ➞ false
I just don't understand how the section (x => x) evaluates to either truthy or falsy. Can someone explain how this works? I hope this makes sense lol. Thanks!
With .every, if any of the return values from the callback are falsey, the .every evaluates to false, otherwise it evaluates to true. So x => x as a callback means: take every value in the array and return it immediately. If all are truthy, the whole .every evaluates to true, else false.
It's doing the same logic as this:
const nothingIsNothing = (...args) => {
for (const arg of args) {
if (!arg) return false;
}
return true;
};
Or, implementing something similar to .every yourself:
// don't do this in real code, this is just an example
Array.prototype.myEvery = function(callback) {
for (const item of this) {
if (!callback(item)) return false;
}
return true;
};
console.log([1, 2, 3].myEvery(x => x));
console.log([1, 2, 3, 0].myEvery(x => x));
Its a combinations of a couple of things
Javascript implicit return statement.
getVal = a => a;
is the same as
function getVal(a) { return a }
every web API method run until it encounters a falsy (not false) value. Below is a quote from MDN.
The every method executes the provided callback function once for each
element present in the array until it finds the one where callback
returns a falsy value. If such an element is found, the every method
immediately returns false. Otherwise, if callback returns a truthy
value for all elements, every returns true.
param => param is the same as (param) => { return param }
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
These are all the falsy values in JavaScript: https://developer.mozilla.org/en-US/docs/Glossary/Falsy
The documentation for the return value of every states the following:
true if the callback function returns a truthy value for every array
element. Otherwise, false.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every
So something like this will be false as not all elements are truthy
const x = ['test', 0, null, -0].every(el => el);
console.log(x);
But something like this will return true as all elements are truthy values
const x = ['test', 1, 'hi', 10].every(el => el);
console.log(x);
As per the docs the every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value i.e true if the callback function returns a truthy value for every array element. Otherwise, false.
const nothingIsNothing = (...args) => args.every(x=>x) can be expanded to:
const nothingIsNothing = (...args) => args.every(function(x){
if(x)
return true
else
return false
})
Here is another version which will help you understand the shorthand better. The value x is typecasted to a boolean and true/false is returned.
const nothingIsNothing = (...args) => args.every(Boolean)
console.log(nothingIsNothing(0, false, undefined, null))
console.log(nothingIsNothing(33, "Hello", true, []))
The Array.prototpe.every() does the heavy lifting here.
The every() method tests whether all elements in the array pass the
test implemented by the provided function. It returns a Boolean value.
The PolyFil following the ECMA-262, 5th specification, assuming Object and TypeError have their original values, and that callbackfn.call evaluates to the original value of Function.prototype.call, demonstrate the internal behavior nicely:
Array.prototype.PolyFillEvery = function(callbackfn, thisArg) {
'use strict';
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the this
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method
// of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
if (typeof callbackfn !== 'function' && Object.prototype.toString.call(callbackfn) !== '[object Function]') {
throw new TypeError();
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Let k be 0.
k = 0;
// 7. Repeat, while k < len
while (k < len) {
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
var testResult;
// i. Let kValue be the result of calling the Get internal method
// of O with argument Pk.
kValue = O[k];
// ii. Let testResult be the result of calling the Call internal method
// of callbackfn with T as the this value if T is not undefined
// else is the result of calling callbackfn
// and argument list containing kValue, k, and O.
if(T) testResult = callbackfn.call(T, kValue, k, O);
else testResult = callbackfn(kValue,k,O)
// iii. If ToBoolean(testResult) is false, return false.
if (!testResult) {
return false;
}
}
k++;
}
return true;
};
const arFalsey = [0, false, undefined, null];
const arTruthy = [33, "Hello", true, []];
console.log(arFalsey.PolyFillEvery(x=>x)); //false
console.log(arTruthy.PolyFillEvery(x=>x)); //true
console.log([true,false].PolyFillEvery(x=>x)); //false
The crucial part is if-clause in the inside of the loop:
// iii. If ToBoolean(testResult) is false, return false.
if (!testResult) {
return false;
}
As soon as one of the elements is not tested truthy false is returned; the spread (...) expression is simply used to iterate the array and instead of a traditional function an arrow function x => x is used to feed (via return) each element as is to the test in the every function.

How are array methods aware of the values they are called on?

Can someone explain to me how are array methods aware of the value that we called them on,
As part of the prototype inheritance shouldn't it exist on the Array.prototype
if we say
let animals = ['dog','cat']
animals.map( x => console.log(x))
//dog
//cat
I just don't understand how is map aware of that we passed ['dog','cat'].
I usually see that if you call a function then you need to call it like map(animals).
thank you in advance
or looking at the map polyfill where is the line that we assign it to the arguments of the array.
if (!Array.prototype.map) {
Array.prototype.map = function(callback/*, thisArg*/) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
Array.prototype.mymap = function(callback) {
var myArray = this; // here is the magic
var newArray = [];
for (var i = 0; i < myArray.length; i++) {
newArray.push(callback(myArray[i]));
}
return newArray;
};
console.log([0, 1, 2, 3].mymap(a => a * 2));
Well if we looked at the definition of Map according to W3Schools:
The map() method creates a new array with the results of calling a
function for every array element.
So the function map checks every element and does something with that.
In this example you say: "Console.log every element in this array"
So it's logic that the function map is aware what is in the array.
map() is a method of the Array object. In JavaScript, we say that the animals object uses "prototypical inheritance" of the Array object. It's kind of like saying animals inherits the properties and method of the Array base class (if you come from a world of OOP).
Since map is a function that exists for all Array objects, animals is no exception.
By definition map() takes a function, and returns an Array. It then iterates through each element of the array it was called from (in this case the animals array), and applies the passed function to each element.
Usually you would use this with a return statement in order to generate a new array. For instance, you could write something like:
var upperCaseAnimals = animals.map(x => return(x.toUpperCase()))
This would create a new array, upperCaseAnimals which contains all elements of the animals array with toUpperCase() applied to them.
But you can also use it to "do something" with each element of the array. This is what's being done in the sample above. Instead of giving a return value for each element, you're just console.log()ing each element.

Rebuilding reduce and each

Recently had an interview for a programming related gig. The interviewer made me rewrite each first, this I had no problem with and understood completely. Heres my each method:
var each = function(arrayItems,callback){
//if arrayItems is not an array
if(!Array.isArray(arrayItems)){
//write a for in loop to iterate through the object
for(var key in arrayItems){
//store the value, the key and the whole object as the callback parameters
callback(arrayItems[key],key,arrayItems);
}
}
//if arrayItems wasn't an object iterate through the array
for(var i = 0; i < arrayItems.length; i++){
//store the value,key and whole array as the callback's parameters
callback(arrayItems[i],i,arrayItems);
}
};
Second he had my rewrite reduce this no matter how many times I research devdocs and pick apart every piece of code I have trouble understanding here's my method:
var reduce = function(array,callback,initialValue){
// Implementing each into reduce
each(array,function(number){
//This is the line of code that confuses me
initialValue = callback(initialValue,number);
});
};
I'm looking for somebody to elaborate on the second line of code in reduce. How does this work initialValue is a function with initialValue and number as the parameters. Do initialValue and number need to be in a certain order? How does it work that initial value is equal to a function with intialValue and number as the callback? Also how does it know to execute the code if its something like : [number(s)].reduce(function(a,b){return a + b;},intialValue) I know these questions may seem a little vague, the interview is long gone but as a personal challenge I want to understand what is going on better.
"How does this work initialValue is a function with initialValue and number as the parameters."
I assume you mean callback is a function. If so, yes, it will be passed arguments, but more than just two.
The first is what you have as initialValue, though this adds confusion, because after the first time you update it, it's no longer the initial value. Better to use a different variable name.
The second is the current item in the iteration. You have it a name number, but it may not be a number. Again a confusing name.
The third should be the index of the current iteration.
The fourth should be the original collection.
"Do initialValue and number need to be in a certain order?"
Of course. That's the "accumulator" of your final value and the value of the current iteration. The user needs to know which is which.
"How does it work that initial value is equal to a function with intialValue and number as the callback?"
Every iteration, the callback is supposed to return the updated value of the accumulator. That value gets passed as the first argument of the next iteration.
"Also how does it know to execute the code if its something like : [number(s)].reduce(function(a,b){return a + b;},intialValue)"
That's an odd example, but if you had a correct Array, and you passed something like 0, then a is the accumulator, which will be equal to either the initialValue that you passed, or the return value of the previous iteration.
A more reasonable example of the use of .reduce() would be:
var result = [2,4,3,8,6].reduce(function(acc, curr, i, arr) {
console.log(acc, curr);
return acc + curr;
}, 0);
So on the first iteration, acc (short for accumulator) will be 0 (the initial value given), and curr (short for current) will be the number 2, which is the first item in the Array.
The return value is then 0 + 2.
On the second iteration, acc is the value of the last return, which was 0 + 2 or 2, and curr is the second item in the Array, which is 4.
The return value is then 2 + 4.
On the third iteration, acc is the value of the last return, which was 2 + 4 or 6, and curr is the third item in the Array, which is 3.
The return value is then 6 + 3.
...and so on.
So as you can see, it's just taking either the intial value, or the return value of the previous iteration, passing it as the first argument, letting you do whatever manipulation you want, and then taking your return value and passing it as the first argument of the next iteration.
This continues until the loop is complete, at which point .reduce() gives you whatever you returned from the last iteration.
Note that neither of your functions are ECMAScript compliant. The first one operates on plain objects??? And both are missing certain details.
You may check the underscore core functions!
if (typeof (/./) !== 'function') {
_.isFunction = function(obj) {
return typeof obj === 'function';
};
}
_.bind = function(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
_.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
};
_.each = function(obj, iterator, context) {
if (obj == null) return obj;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
return obj;
};
_.reduce = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduce && obj.reduce === nativeReduce) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
}
each(obj, function(value, index, list) {
if (!initial) {
memo = value;
initial = true;
} else {
memo = iterator.call(context, memo, value, index, list);
}
});
if (!initial) throw new TypeError(reduceError);
return memo;
};
I guess it depends on if you want forEach and reduce to be similar (simple but not to spec) or as close as possible/reasonable to the ECMA5 spec. To best understand them, I would suggest reading the specifications.
Array.prototype.forEach ( callbackfn [ , thisArg ] )
callbackfn should be a function that accepts three arguments. forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.
If a thisArg parameter is provided, it will be used as the this value for each invocation of callbackfn. If it is not provided, undefined is used instead.
callbackfn is called with three arguments: the value of the element, the index of the element, and the object being traversed.
forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.
The range of elements processed by forEach is set before the first call to callbackfn. Elements which are appended to the array after the call to forEach begins will not be visited by callbackfn. If existing elements of the array are changed, their value as passed to callback will be the value at the time forEach visits them; elements that are deleted after the call to forEach begins and before being visited are not visited.
When the forEach method is called with one or two arguments, the following steps are taken:
Let O be the result of calling ToObject passing the this value as the argument.
Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
Let len be ToUint32(lenValue).
If IsCallable(callbackfn) is false, throw a TypeError exception.
If thisArg was supplied, let T be thisArg; else let T be undefined.
Let k be 0.
Repeat, while k < len
Let Pk be ToString(k).
Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
If kPresent is true, then
Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
Call the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
Increase k by 1.
Return undefined.
The length property of the forEach method is 1.
NOTE The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the forEach function can be applied successfully to a host object is implementation-dependent.
-
Array.prototype.reduce ( callbackfn [ , initialValue ] )
callbackfn should be a function that takes four arguments. reduce calls the callback, as a function, once for each element present in the array, in ascending order.
callbackfn is called with four arguments: the previousValue (or value from the previous call to callbackfn), the currentValue (value of the current element), the currentIndex, and the object being traversed. The first time that callback is called, the previousValue and currentValue can be one of two values. If an initialValue was provided in the call to reduce, then previousValue will be equal to initialValue and currentValue will be equal to the first value in the array. If no initialValue was provided, then previousValue will be equal to the first value in the array and currentValue will be equal to the second. It is a TypeError if the array contains no elements and initialValue is not provided.
reduce does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.
The range of elements processed by reduce is set before the first call to callbackfn. Elements that are appended to the array after the call to reduce begins will not be visited by callbackfn. If existing elements of the array are changed, their value as passed to callbackfn will be the value at the time reduce visits them; elements that are deleted after the call to reduce begins and before being visited are not visited.
When the reduce method is called with one or two arguments, the following steps are taken:
Let O be the result of calling ToObject passing the this value as the argument.
Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
Let len be ToUint32(lenValue).
If IsCallable(callbackfn) is false, throw a TypeError exception.
If len is 0 and initialValue is not present, throw a TypeError exception.
Let k be 0.
If initialValue is present, then
Set accumulator to initialValue.
Else, initialValue is not present
Let kPresent be false.
Repeat, while kPresent is false and k < len
Let Pk be ToString(k).
Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
If kPresent is true, then
Let accumulator be the result of calling the [[Get]] internal method of O with argument Pk.
Increase k by 1.
If kPresent is false, throw a TypeError exception.
Repeat, while k < len
Let Pk be ToString(k).
Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
If kPresent is true, then
Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
Let accumulator be the result of calling the [[Call]] internal method of callbackfn with undefined as the this value and argument list containing accumulator, kValue, k, and O.
Increase k by 1.
Return accumulator.
The length property of the reduce method is 1.
NOTE The reduce function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the reduce function can be applied successfully to a host object is implementation-dependent.
Which for me I would write (and these are not 100% to spec, but close). You could of course write them exactly as described in the specs above.
Helper functions
function firstToCapital(inputString) {
return inputString.charAt(0).toUpperCase() + inputString.slice(1).toLowerCase();
}
function isClass(inputArg, className) {
return Object.prototype.toString.call(inputArg) === '[object ' + firstToCapital(className) + ']';
}
function throwIfNotAFunction(inputArg) {
if (!isClass(inputArg, 'function')) {
throw TypeError('Argument is not a function');
}
return inputArg;
}
Abstracts described in the speciications
function checkObjectCoercible(inputArg) {
if (typeof inputArg === 'undefined' || inputArg === null) {
throw new TypeError('Cannot convert argument to object');
}
return inputArg;
};
function ToObject(inputArg) {
checkObjectCoercible(inputArg);
if (isClass(inputArg, 'boolean')) {
inputArg = new Boolean(inputArg);
} else if (isClass(inputArg, 'number')) {
inputArg = new Number(inputArg);
} else if (isClass(inputArg, 'string')) {
inputArg = new String(inputArg);
}
return inputArg;
}
function ToUint32(inputArg) {
return inputArg >>> 0;
}
forEach
function forEach(array, fn, thisArg) {
var object = ToObject(array),
length,
index;
throwIfNotAFunction(fn);
length = ToUint32(object.length);
for (index = 0; index < length; index += 1) {
if (index in object) {
fn.call(thisArg, object[index], index, object);
}
}
}
reduce
function reduce(array, fn, initialValue) {
var object = ToObject(array),
accumulator,
length,
kPresent,
index;
throwIfNotAFunction(fn);
length = ToUint32(object.length);
if (!length && arguments.length === 2) {
throw new TypeError('reduce of empty array with no initial value');
}
index = 0;
if (arguments.length > 2) {
accumulator = initialValue;
} else {
kPresent = false;
while (!kPresent && index < length) {
kPresent = index in object;
if (kPresent) {
accumulator = object[index];
index += 1;
}
}
if (!kPresent) {
throw new TypeError('reduce of empty array with no initial value');
}
}
while (index < length) {
if (index in object) {
accumulator = fn.call(undefined, accumulator, object[index], index, object);
}
index += 1;
}
return accumulator;
}
On jsFiddle

Angular equivalent of jQuery $.map?

I'm transitioning from relying on jQuery to building apps in AngularJS. It's recommended in a number of places to not mix jQuery and Angular code.
One thing I miss though is the jQuery $.map function for arrays. I know this could be re-written using the native Javascript map function, but this is not implemented in all browsers (notably, IE < v9).
So, is there an Angular equivalent, or should I got back to writing for (var x = 0; x < foo; x += 1) {...} so I can stop including jQuery?
UPDATE Sometimes knowing what to search for is all you need. Bergie says 'look for polyfills'. Here's a reference guide (from the Modernizr crew) for a bunch of resources for making modern code work on older browsers: HTML5 Cross Browser Polyfills
Check here: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
Mozilla has supplied an Array.map polyfill for unsupported browsers
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
No, there is no equivalent in Angular. And as you discovered, no you don't need to fall back to writing imperative code.
Instead, just use the map function that is built directly into JavaScript. If you need to support IE8, insert the polyfill at the beginning of your scripts.

Javascript: Having trouble with .map() on IE

This code runs great on Chrome, FFX, etc. It takes the content of a textarea and separates all lines in different array items (new lines are represented by empty array items). When testing it on IE, it throws an error. Code:
This is tregex's value and the call:
var tregex = /\n|([^\r\n.!?]+([.!?]+|$))/gim;
var source = $('#text').val().match(tregex).map($.trim);
The code throws this error message because of .map() (IE only)
User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1;
Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR
3.5.30729) Timestamp: Fri, 13 Jul 2012 21:52:48 UTC
Message: Object doesn't support this property or method Line: 128
Char: 6 Code: 0 URI: http://mydomain.com/src/common.js
Why? Any way I can support it on IE7+? (this was tested on IE8).
IE is a terrible browser, and as such doesn't have a built-in map function (at least not in IE7-8). Since you're trying to call map on the results of a Regular Expression match (as opposed to calling it on a jQuery results object), the only map you can use is the built-in one (that IE doesn't have).
There are many libraries that simulate map for you however, including jQuery, Underscore, and Mochikit.
Here's an example of how you could use jQuery's to do what you're trying to do:
$.map($('#text').val().match(tregex), $.trim);
I believe your code may be working in FF and Chrome by accident. Did you mean to use jQuery.map? You are using Array.map which isn't supported in IE prior to 9.
Consider the following as a replacement.
var source = $.map($('#text').val().match(tregex), $.trim);
This uses jQuery's map implementation to loop through and do the trim.
I'm fairly sure Array.map() was only added in IE9. You should loop through the array manually instead.
You can add the support just by including the shim for it:
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
You can also include the es5shim which adds .map and all the other missing array methods in IE7-8 plus other goods like Function#bind

Categories

Resources