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).
Related
Studying the polyfill for the find method written on the MDN web docs, there's a particular line that I'm not following, let me share the code
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
if (this == null) {
throw TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw 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
});
}
My question is with the expression var o = Object(this);. What's the purpose of doing so instead of doing var o = this?. Printing the value in both described cases returns the same object.
Is this an abbreviated way of calling var o = new Object(this);?
I have removed the comments from the method to shorten the text, here's the link to the polyfill implementation.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill
Thanks!
In strict mode, this isn't always an object. Object(this) makes sure that o is an object, not a primitive.
Here's an example of this being a primitive:
"use strict";
Object.defineProperty(String.prototype, "nishCap", {
writable: true,
configurable: true,
value() {
console.log(typeof this); // "string"
const o = Object(this);
console.log(typeof o); // "object"
return o.substring(0,1).toUpperCase() + o.substring(1);
}
});
const capped = "foo".nishCap();
Note that this even applies to array methods, because you can call them on non-arrays, like Array.prototype.find.call("foo", ch => ch === "o").
Is this an abbreviated way of calling var o = new Object(this);?
No, new Object always creates a new object (and doesn't use the argument you give it). When you call Object as a function, it coerces its argument to object. So a primitive string becomes a String object, a primitive number becomes a Number object, etc.
What's the purpose of doing so instead of doing var o = this?
That polyfill is fairly closely following the spec, which starts out with:
Let O be ? ToObject(this value).
In most cases it wouldn't be important, but I wouldn't be surprised if there were some edge case where leaving it out would cause observable behavior at variance with the spec.
Because Array.prototype.find can be called with a this value which is not an object. See the specification:
When the find method is called, the following steps are taken:
Let O be ? ToObject(this value).
So, in order to be perfectly compliant with the specification, the polyfill needs Object(this). Otherwise, the implementations will not be the same, as you can see by the following two snippets:
'use strict';
const str = 'abc';
Array.prototype.find.call(
str,
(char, i, theThis) => {
// theThis should be an object, even if called on a non-object:
console.log(theThis);
}
);
'use strict';
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
if (this == null) {
throw TypeError('"this" is null or not defined');
}
// Without object wrapping:
var o = this; // <-------------------------------
var len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw 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
});
const str = 'abc';
Array.prototype.find.call(
str,
(char, i, theThis) => {
// The polyfill above had no object wrapping, so this result is not the same:
console.log(theThis);
}
);
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
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);
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)
For example, in the below object, I want to extract first three values of the value and make a new simple array { -0.30771, 1.0031, 0.0001}. Why is the expression like ts.slice(0,4).value impossible ?
ts = [
{time: "1",
value: -0.30771},
{time: "2",
value: 1.0031 },
{time: "3",
value: 0.0001 },
...
]
As #FelixKling noted, this is being intialized as an object, not an array (due to the use of {} ). Because objects don't allow duplicate keys, the end result of this assignment operation is going to be:
ts = {time:"3", value:0.0001}
So you don't even have 3 'value's to choose from. I would suggest restructuring your data, perhaps to something like this:
ts = [
{time: "1",value: -0.30771},
{time: "2",value: 1.0031},
{time: "3",value: 0.0001},
]
Then you could use something like map to collect them:
ts.map(function (v, idx, array) { return v.value; })
The link to map also contains a polyfill, in case you need it.
ts = [
{time: "1",value: -0.30771},
{time: "2",value: 1.0031},
{time: "3",value: 0.0001},
];
values = ts.map(function (el, idx, array) { return el.value; });
document.write(values);
// 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;
};
}
If you don't mind using Underscore, then just
_.pluck(ts, 'value')