Array Reduce Polyfill Explanation - javascript

Apologize in advance for lengthy post. I am trying to understand array reduce polyfill provided by MDN. I could not understand some lines in the polyfill can you explain it please. Below is the code
if (!Array.prototype.reduce) {
Object.defineProperty(Array.prototype, 'reduce', {
value: function(callback /*, initialValue*/) {
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');
}
// 1. Let O be ? ToObject(this value).
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// Steps 3, 4, 5, 6, 7
var k = 0;
var value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k < len && !(k in o)) {
k++;
}
// 3. If len is 0 and initialValue is not present,
// throw a TypeError exception.
if (k >= len) {
throw new TypeError( 'Reduce of empty array ' +
'with no initial value' );
}
value = o[k++];
}
// 8. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kPresent be ? HasProperty(O, Pk).
// c. If kPresent is true, then
// i. Let kValue be ? Get(O, Pk).
// ii. Let accumulator be ? Call(
// callbackfn, undefined,
// « accumulator, kValue, k, O »).
if (k in o) {
value = callback(value, o[k], k, o);
}
// d. Increase k by 1.
k++;
}
// 9. Return accumulator.
return value;
}
});
}
Question1: If you see step 1,
var o = Object(this);
I have checked both values of o and this, by passing an array to the polyfill method. There is no difference between o and this. They both are arrays(array.isarray returned true on both) with the same array value. Why not use below instead..?
var o = this;
Question2: Step 2
var len = o.length >>> 0;
Above line seems to right shift the o.length(32 bits). However no.of bits shifted is 0. So what advantage do we get by shifting 0 bits... Why not use below instead...?
var len = o.length;
Question 3: The first while condition inside else as below
while (k < len && !(k in o)) {
k++;
}
Initially k is set to 0 and it always seems to exist in o. So this while loop condition never gets to be true. So why do we need this while loop, if it never gets inside.

Question 1:
To make sure reduce is called on an object as reduce could be called through Function#call, Function#apply or even bound Function#bind:
Array.prototype.reduce.call(undefined, function() {});
So when accessing properties such as length, an error saying can't access property **** of undefined won't be thrown.
NOTE: the example above uses the native reduce which actually throws an error if not provided with an object.
Question 2:
To always have a valid integer value as length (even if it doesn't exist):
console.log(5 >>> 0); // 5
console.log(5.5 >>> 0); // 5
console.log("5" >>> 0); // 5
console.log("hello" >>> 0); // 0
console.log(undefined >>> 0); // 0
Question 3:
To deal with sparse arrays:
var arr = [5, 6];
arr[7000000] = 7;
arr.reduce(function(acc, v, i) {
console.log("index:", i);
}, 0);
It won't go through all the indices from 0 to 7000000, only those that really exist.

The following approach works :
var Arr = [1,2,3,4]
Array.prototype.myreduce = function(callback,initialvale){
var result ;
var resultvalue = initialvale
for(var key =0;key<this.length;key++){
var resultvalue =callback(resultvalue,this[key])
}
return resultvalue;
}
var customvalued = Arr.myreduce(function(total,value){
//console.log(total,value)
if(value%2==0){
total.push(value)
}
return total
},[])
console.log(customvalued)

Related

Confused about polyfill of Array.prototype.reduce [duplicate]

This question already has answers here:
Why checking null in Array.prototype.forEach()?
(1 answer)
Object() without the new keyword or .create method
(1 answer)
Array Reduce Polyfill Explanation
(2 answers)
JavaScript 'in' operator for `undefined` elements in Arrays
(3 answers)
Closed 4 years ago.
This code is polyfill of Array.prototype.reduce given on Mozilla Developer Network.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#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')
}
var O = Object(this)
var len = O.length >>> 0
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function')
}
if (arguments.length > 1) {
T = arguments[1]
}
A = new Array(len)
k = 0
while (k < len) {
var kValue, mappedValue
if (k in O) {
kValue = O[k]
mappedValue = callback.call(T, kValue, k, O)
A[k] = mappedValue
}
k++
}
return A
}
}
What I don't understand is these two lines
1.Why not just use this?
var O = Object(this)
2.Is it possible this be null, why need this code below?
if (this == null) {
throw new TypeError('this is null or not defined')
}
3.Why we need k in O? while k < len, k always in O, is it useless condition?
if (k in O) {
kValue = O[k]
mappedValue = callback.call(T, kValue, k, O)
A[k] = mappedValue
}
1.Why not just use this?
var O = Object(this)
In Edition 3, an undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.
So my guess is that the reasons this is being done is to keep consistency.
2.Is it possible this be null, why need this code below?
if (this == null) {
throw new TypeError('this is null or not defined')
}
Yes, it is possible for this to be null.
Execute the following code with and without strict mode. You will notice that in strict mode the output is null, while in the other case its the window.
// "use strict";
var x = function(){
console.log(this);
return this;
}
x.call(null);
3.Why we need k in O? while k < len, k always in O, is it useless condition?
if (k in O) {
kValue = O[k]
mappedValue = callback.call(T, kValue, k, O)
A[k] = mappedValue
}
Not a useless condition, because it checks if a property exists.(see in operator examples)
Adding an example with sparse arrays:
var a = new Array(3);
console.log(a); // [ , , ]
console.log(a.length); // 3
console.log(a[0]); // undefined

refactorized solve for an algorithm in javascript

I have attended a technical interview for a development company. They asked me the following:
Giving an array of numbers (n) find 2 numbers that sum gives (k) and print them.
e.g
Input: n = [2,6,4,5,7,1], k = 8
Output: result=(2,6),(7,1)
My solution:
function findSum(n,k){
let aux = []
for (let i = 0; i < n.length; i++) {
for (let j = i+1; j < n.length; j++) {
if (n[i] + n[j] == k) {
aux.push({ first: n[i], second: n[j] })
}
}
}
return aux;
}
They told me that, it is possible to make the exercise with some kind of key or mapping.
Does some one know how to do it with only one loop?
The key to solving a question like this with low time complexity is the ability to efficiently search the data structure. A lot of answers rearrange the array in a way where searching an array is optimized. Another approach is with a data structure that inherently has fast search.
Set and Map data structures have O(1) time complexity for searches, which make them good data structures where searching can be leveraged to increase performance.
I use a new Map and traverse the array while adding it as a key. I set the key to the number and the value to the number of times I see it. I use a map over a new Set because I can also keep track of the number of instances of that particular number.
I search for the number that would sum up to k, which is: (k - num). If I find that number, I add both numbers to my results data structure and decrement the value by 1, to show that it's been used.
Time complexity: O(n), memory complexity: O(2n). Twice the amount of space compared to the original array because I have a key and a value to store in my Map
function pairSums(arr, k){
const map = new Map
const matches = []
for (let num of arr) {
const search = k - num
if (map.get(search) > 0) {
matches.push([num, k - num])
map.set(search, map.get(search) - 1)
} else if (!map.has(num)){
map.set(num, 1)
} else {
map.set(num, map.get(num) + 1)
}
}
return matches
}
console.log(pairSums([2, 6, 6, 6, 2, 4, 4, 4, 5, 7, 1, 4, 2], 8))
Match a number x from array with a key Math.min(x, k - x). Then run through your array and store every number in a hash using mentioned key. When the key you are going to add already is in the hash - check if stored value and current number gives required sum.
function findSum(n, k){
let hash = {};
for(let i = 0; i < n.length; ++i){
let x = n[i], key = Math.min(x, k - x);
if((key in hash) && hash[key] + x == k)
return [hash[key], x];
else hash[key] = x;
}
}
A task like this can be as simple or as complicated as you want to make it. Here's one solution, for example:
function findPairs(n, k) {
return n.reduce((pairs, next, i) => pairs.concat(
n.slice(i + 1)
.filter(num => next + num === k)
.map(num => [ next, num ])
),
[]
);
}
For the inputs [2, 6, 4, 5, 7, 1] and 8 will output [ [2, 6], [7, 1] ].
From https://www.geeksforgeeks.org/write-a-c-program-that-given-a-set-a-of-n-numbers-and-another-number-x-determines-whether-or-not-there-exist-two-elements-in-s-whose-sum-is-exactly-x/:
Sort the array in non-decreasing order.
Initialize two index variables to find the candidate elements in the sorted array. Initialize l to the leftmost index: l = 0, Initialize r to the rightmost index: r = n.length - 1
Loop while l < r.
if (n[l] + n[r] == k) then return 1
else if( n[l] + n[r] < k ) then l++
else r--
No candidates in whole array - return 0
I think by sorting you can do that
var n = [2,6,4,5,7,1];
var k = 8 ;
n.sort();
let start = 0, end = n.length-1;
while(start < n.length && end >= 0) {
let current_sum = (n[start] + n[end]);
if(current_sum == k) {
console.log('Found sum with '+ n[start] +' and '+ n[end]);
break;
}
else if(current_sum > k) {
end--;
} else {
start++;
}
}
if(start == n.length || end < 0) {
console.log('Not Found');
}
but while writing this code I got one another approach also
const set = new Set([2,6,4,5,7,1]);
var k = 8;
let found = false;
for (let item of set) {
let another = k - item;
if(set.has(another)){
console.log('found with '+item +' and ' +another);
found = true;
break;
}
}
if(!found) {
console.log('Not found');
}
If numbers are non-negative and the target value is within JavaScript array limit:
function findsums(arr,k){
var ret=[];
var aux=[];
arr.forEach(function(i){
if(i<=k){
if(aux[k-i])
ret.push([k-i,i]);
aux[i]=true;
}
});
return ret;
}
console.log(findsums([2,6,4,5,7,1],8));
Similar approach could work with a bitfield (or even with a sparse array of bitfields) too.
Minified alternative similar to #Andrew's great answer, but assumes that all numbers are above 0 :
var pairs = (arr, k) => arr.reduce((a, n) =>
(a[n - k]-- ? a.push([n, k - n]) : a[-n] = a[-n] | 0 + 1, a), []);
console.log(JSON.stringify( pairs([2,6,4,5,7,1], 8) ));

Iterate through ALL values in a collection before returning true or false

I was wondering if there's more "functional" way to do this. Meaning, rather than having to do something like this:
let flag = true;
[1, 2, 3].forEach(n => if (n > 2) flag = false);
return flag;
I'm looking for something closer to this:
return [1, 2, 3].overEvery(n => n > 2);
The closest solution I've found is the Array.prototype.every function, but it terminates once it returns false, without iterating through the rest of the values in the collection.
Reason why I don't want to terminate is because I want to iterate through ALL fields in a form to display all the form errors before returning true or false in the form's onsubmit handler.
You can use Array.filter, which will return the elements that failed the validation if you return true for the elements that should fail.
Here is another approach:
function a()
{
var flag = true;
[1, 2, 3].forEach(function(value) { if(value > 2) flag = false; });
return flag;
}
console.log(a());
You can do a new prototype function that is like every but checks all the records:
if (!Array.prototype.everyCheckAll) {
Array.prototype.everyCheckAll = 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') {
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
var oneFalse = false;
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. Let testResult be the result of calling the Call internal method
// of callbackfn with T as the this value and argument list
// containing kValue, k, and O.
var testResult = callbackfn.call(T, kValue, k, O);
// iii. If ToBoolean(testResult) is false, return false.
if (!testResult) {
oneFalse = true;
}
}
k++;
}
return !oneFalse;
};
}
function gt2(element, index, array) {
return element > 2;
}
document.write([1,2,3].everyCheckAll(gt2)); // false
document.write([4,5,6].everyCheckAll(gt2)); // true
Use Array#every, and check that every number is not greater than 2. Another advantage of Array#every is that whenever the callback returns false, the iteration stops, and the result is returned.
const flag = [1, 2, 3].every((n) => n <= 2);
console.log(flag);

Convert object into array in IE (Javascript)

can I convert , in Javascript, an object into an array in Internet Explorer? I read that the method Array.from(obj) is not supported from IE. It is correct?
Thank you
You can verify for yourself on On Mozilla's MDN that Array.from() isn't supported by IE :
On that same page, you can also find the following polyfill to add support of Array.from() to browsers that don't support it natively :
// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
Array.from = (function () {
var toStr = Object.prototype.toString;
var isCallable = function (fn) {
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
};
var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) { return 0; }
if (number === 0 || !isFinite(number)) { return number; }
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};
// The length property of the from method is 1.
return function from(arrayLike/*, mapFn, thisArg */) {
// 1. Let C be the this value.
var C = this;
// 2. Let items be ToObject(arrayLike).
var items = Object(arrayLike);
// 3. ReturnIfAbrupt(items).
if (arrayLike == null) {
throw new TypeError('Array.from requires an array-like object - not null or undefined');
}
// 4. If mapfn is undefined, then let mapping be false.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new TypeError('Array.from: when provided, the second argument must be a function');
}
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 2) {
T = arguments[2];
}
}
// 10. Let lenValue be Get(items, "length").
// 11. Let len be ToLength(lenValue).
var len = toLength(items.length);
// 13. If IsConstructor(C) is true, then
// 13. a. Let A be the result of calling the [[Construct]] internal method
// of C with an argument list containing the single item len.
// 14. a. Else, Let A be ArrayCreate(len).
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
// 16. Let k be 0.
var k = 0;
// 17. Repeat, while k < len… (also steps a - h)
var kValue;
while (k < len) {
kValue = items[k];
if (mapFn) {
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
} else {
A[k] = kValue;
}
k += 1;
}
// 18. Let putStatus be Put(A, "length", len, true).
A.length = len;
// 20. Return A.
return A;
};
}());
}
Note that it comes with the following remarks :
This algorithm is
exactly the one specified in ECMA-262, 6th edition, assuming Object
and TypeError have their original values and that callback.call
evaluates to the original value of Function.prototype.call. In
addition, since true iterables can not be polyfilled, this
implementation does not support generic iterables as defined in the
6th edition of ECMA-262.
That means that there are a few caveats, but it should be more than sufficient for most purposes!
Yes, according to ECMAScript 6, this true for elder IE. You can find some polyfills listed there if you need this function & support for elder IE.
Array.from method is a method that came with ECMAScript 6
you can see on this page that the support for ECMAScript 6 in IE is not very good. Look at the examples in the below question for a solution to your problem
Converting a JS object to an array
As in JavaScript, array positions are like object properties (You can access objects with obj["property"]), you can just iterate over the properties of your object and push them onto an array.
For example:
//Example object
var obj = {
prop1: "asd",
prop2: "Another value",
prop3: 5,
funcprop: function(val){return val*2;}
}
//-----------
var i = 0;
var array = [];
for(prop in obj){
array[i] = obj[prop];
i++;
}
console.log(array); //Array [ "asd", "Another value", 5, funcprop() ]
Acording to MSDN, for..in syntax is valid since IE6.
Take this with care, as you will have property functions in the array positions also.

What is the use of length property of an Object in Javascript?

This code is polyfill of Array.prototype.map given on Mozilla Developer Network. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#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 (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 = 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, k, {
// 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;
};
}
What I do not understand is these two lines -
var O = Object(this);
var len = O.length >>> 0;
Can someone please explain this to me? What is the use of calling length property on an Object(which has become an array after passing 'this' to it, I suppose) and then zero-fill right shifting it by 0?
Obviously, it needs the length in order to iterate over the elements of the array.
You don't really need to worry about the Object(this). If this is an array, it does nothing. This type of coding is to deal with certain kinds of objects which are not arrays. For instance, I can invoke map as Array.prototype.map.call(5, function() { }) and it will work (returning []). In this case, the line you are wondering about turns 5 into an object, whose length property I can examine (although in that case it doesn't exist; the >>> 0 idiom will transform the undefined into 0).

Categories