Created
November 14, 2011 18:13
-
-
Save yuku/1364652 to your computer and use it in GitHub Desktop.
ECMAScript 5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 8.6.2 Object Internal Properties and Methods | |
// Evenry ECMAScript object has a Boolean-valued [[Extensible]] internal | |
// property that controls whether or not named properties may be added to the | |
// object. If the value of the [[Extensible]] internal property is false then | |
// additional named properties may not be added to the object. In addition, if | |
// [[Extensible]] is false the value of the [[Class]] and [[Prototype]] | |
// internal properties of the object may not be modified. Once the value of an | |
// [[Extensible]] internal property has been set to false it may not be | |
// subsequently changed to true. | |
Object.defineProperty(Object.prototype, 'Extensible', { | |
value: true, writable: false, enumerable: false, configurable:false | |
}); | |
// 8.10.1 IsAccessorDescriptor(Desc) | |
var IsAccessorDescriptor = function(Desc) { | |
// 1. If Desc is undefined, then return false. | |
if (Desc === undefined) { | |
return false; | |
} | |
// 2. If both Desc.[[Get]] and Desc.[[Set]] are absent, then return false. | |
if (Desc.set === undefined && Desc.get === undefined) { | |
return false; | |
} | |
// 3. Return true. | |
return true; | |
}; | |
// 8.10.2 IsDataDescriptor(Desc) | |
var IsDataDescriptor = function(Desc) { | |
// 1. If Desc is undefined, then return false. | |
if (Desc === undefined) { | |
return false; | |
} | |
// 2. If both Desc.[[Value]] and Desc.[[Writable]] are absent, then return | |
// false. | |
if (Desc.value === undefined && Desc.writable === undefined) { | |
return false; | |
} | |
// 3. Return true. | |
return true; | |
}; | |
// 8.10.3 IsGenericDescriptor(Desc) | |
var IsGenericDescriptor = function(Desc) { | |
// 1. If Desc is undefined, then return false. | |
if (Desc === undefined) { | |
return false; | |
} | |
// 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both | |
// false, then return true. | |
if (!IsAccessorDescriptor(Desc) && !IsDataDescriptor(Desc)) { | |
return true; | |
} | |
// 3. Return false. | |
return false; | |
}; | |
// 8.10.4 FromPropertyDescriptor(Desc) | |
var FromPropertyDescriptor = function(Desc) { | |
// The following algorithm assumes that Desc is a fully populated Property | |
// Descriptor, such as that returned from [[GetOwnProperty]] (see 8.12.1). | |
// 1. If Desc is undefined, then return undefined. | |
if (Desc === undefined) { | |
return undefined; | |
} | |
// 2. Let obj be the result of creating a new object as if by the expression | |
// new Object() where Object is the standard built-in constructor with | |
// that name. | |
var obj = new Object(); | |
// 3. If IsDataDescriptor(Desc) is true, then | |
if (IsDataDescriptor(Desc)) { | |
// a. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "value", Property Descriptor {[[Value]]: Desc.[[Value]], [[Writable]]: | |
// true, [[Enumerable]]: true, [[Configurable]]: true}, and false. | |
obj.DefineOwnProperty("value", { | |
value: Desc.value, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
// b. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "writable", Property Descriptor {[[Value]]: Desc.[[Writable]], | |
// [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, | |
// and false. | |
obj.DefineOwnProperty("writable", { | |
value: Desc.writable, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
} | |
// 4. Else, IsAccessorDescriptor(Desc) must be true, so | |
else { | |
// a. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "get", Property Descriptor {[[Value]]: Desc.[[Get]], [[Writable]]: | |
// true, [[Enumerable]]: true, [[Configurable]]: true}, and false. | |
obj.DefineOwnProperty("get", { | |
value: Desc.get, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
// b. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "set", Property Descriptor {[[Value]]: Desc.[[Set]], [[Writable]]: | |
// true, [[Enumerable]]: true, [[Configurable]]: true}, and false. | |
obj.DefineOwnProperty("set", { | |
value: Desc.set, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
} | |
// 5. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "enumerable", Property Descriptor {[[Value]]: Desc.[[Enumerable]], | |
// [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and | |
// false. | |
obj.DefineOwnProperty("enumerable", { | |
value: Desc.enumerable, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
// 6. Call the [[DefineOwnProperty]] internal method of obj with arguments | |
// "configurable", Property Descriptor {[[Value]]: Desc.[[Configurable]], | |
// [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and | |
// false. | |
obj.DefineOwnProperty("configurable", { | |
value: Desc.configurable, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, false); | |
// 7. Return obj. | |
return obj; | |
}; | |
// 8.10.5 ToPropertyDescriptor(Obj) | |
var ToPropertyDescriptor = function(Obj) { | |
// 1. If Type(Obj) is not Object throw a TypeError exception. | |
if (typeof O !== "object") { | |
throw TypeError; | |
} | |
// 2. Let desc be the result of creating a new Property Descriptor that | |
// initially has no fields. | |
var desc = {}; | |
// 3. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "enumerable" is true, then | |
if (O.HasProperty("enumerable")) { | |
// a. Let enum be the result of calling the [[Get]] internal method of Obj | |
// with "enumerable". | |
var enum = Obj.Get("enumerable"); | |
// b. Set the [[Enumerable]] field of desc to ToBoolean(enum). | |
desc.enumerable = ToBoolean(enum); | |
} | |
// 4. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "configurable" is true, then | |
if (O.HasProperty("configurable")) { | |
// a. Let conf be the result of calling the [[Get]] internal method of Obj | |
// with argument "configurable". | |
var conf = Obj.Get("configurable"); | |
// b. Set the [[Configurable]] field of desc to ToBoolean(conf). | |
desc.configurable = ToBoolean(conf); | |
} | |
// 5. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "value" is true, then | |
if (O.HasProperty("value")) { | |
// a. Let value be the result of calling the [[Get]] internal method of Obj | |
// with argument “value”. | |
var value = Obj.Get("value"); | |
// b. Set the [[Value]] field of desc to value. | |
desc.value = value; | |
} | |
// 6. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "writable" is true, then | |
if (O.HasProperty("writable")) { | |
// a. Let writable be the result of calling the [[Get]] internal method of | |
// Obj with argument "writable". | |
var writable = Obj.Get("writable"); | |
// b. Set the [[Writable]] field of desc to ToBoolean(writable). | |
desc.writable = ToBoolean(writable); | |
} | |
// 7. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "get" is true, then | |
if (O.HasProperty("get")) { | |
// a. Let getter be the result of calling the [[Get]] internal method of | |
// Obj with argument "get". | |
var getter = Obj.Get("get"); | |
// b. If IsCallable(getter) is false and getter is not undefined, then | |
// throw a TypeError exception. | |
if (!IsCallable(getter) && getter !== undefined) { | |
throw TypeError; | |
} | |
// c. Set the [[Get]] field of desc to getter. | |
desc.get = getter; | |
} | |
// 8. If the result of calling the [[HasProperty]] internal method of Obj | |
// with argument "set" is true, then | |
if (O.HasProperty("set")) { | |
// a. Let setter be the result of calling the [[Get]] internal method of | |
// Obj with argument "set". | |
var setter = Obj.Get("set"); | |
// b. If IsCallable(setter) is false and setter is not undefined, then | |
// throw a TypeError exception. | |
if (!IsCallable(setter) && setter !== undefined) { | |
throw TypeError; | |
} | |
// c. Set the [[Set]] field of desc to setter. | |
desc.set = setter; | |
} | |
// 9. If either desc.[[Get]] or desc.[[Set]] are present, then | |
if (desc.get || desc.set) { | |
// a. If either desc.[[Value]] or desc.[[Writable]] are present, then throw | |
// a TypeError exception. | |
if (desc.value || desc.writable) { | |
throw TypeError; | |
} | |
} | |
// 10. Return desc. | |
return desc; | |
}; | |
// 8.12.1 [[GetOwnProperty]](P) | |
Object.prototype.GetOwnProperty = function(P) { | |
var O = this | |
// 1. If O doesn't have an own property with name P, return undefined. | |
if (O[P] === undefined) return undefined; | |
// 2. Let D be a newly created Property Descriptor with no fields. | |
var D = {}; | |
// 3. Let X be O's own property named P. | |
var X = ToPropertyDescriptor(O[P]); | |
// 4. If X is a data property, then | |
if (IsDataDescriptor(X)) { | |
// a. Set D.[[Value]] to the value of X's [[Value]] attribute. | |
D.value = X.value; | |
// b. Set D.[[Writable]] to the value of X's [[Writable]] attribute. | |
D.writable = X.writable; | |
} | |
// 5. Else X is an accessor property, so | |
else { | |
// a.Set D.[[Get]] to the value of X's [[Get]] attribute. | |
D.get = X.get; | |
// b.Set D.[[Set]] to the value of X's [[Set]] attribute. | |
D.set = X.set; | |
} | |
// 6. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute. | |
D.enumerable = X.enumerable; | |
// 7. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. | |
D.configurable = X.configurable; | |
// 8. Return D. | |
return D; | |
}; | |
// 8.12.2 [[GetProperty]](P) | |
Object.prototype.GetProperty = function(P) { | |
var O = this; | |
// 1. Let prop be the result of calling the [[GetOwnProperty]] internal | |
// method of O with property name P. | |
var prop = O.GetOwnProperty(P); | |
// 2. If prop is not undefined, return prop. | |
if (prop !== undefined) { | |
return prop; | |
} | |
// 3. Let proto be the value of the [[Prototype]] internal property of O. | |
var proto = O.__proto__; | |
// 4. If proto is null, return undefined. | |
if (proto === null) { | |
return undefined; | |
} | |
// 5. Return the result of calling the [[GetProperty]] internal method of | |
// proto with argument P. | |
return proto.GetProperty(P); | |
} | |
// 8.12.3 [[Get]](P) | |
Object.prototype.Get = function (P) { | |
var O = this; | |
// 1. Let desc be the result of calling the [[GetProperty]] internal method | |
// of O with property name P. | |
var desc = O.GetProperty(P); | |
// 2. If desc is undefined, return undefined. | |
if (desc === undefined) { | |
return undefined; | |
} | |
// 3. If IsDataDescriptor(desc) is true, return desc.[[Value]]. | |
if (IsDataDescriptor(desc)) { | |
return desc.value; | |
} | |
// 4. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be | |
// desc.[[Get]]. | |
var getter = desc.get; | |
// 5. If getter is undefined, return undefined. | |
if (getter === undefined) { | |
return undefined; | |
} | |
// 6. Return the result calling the [[Call]] internal method of getter | |
// providing O as the this value and providing no arguments. | |
return getter.call(O); | |
}; | |
// 8.12.4 [[CanPut]](P) | |
Object.prototype.CanPut = function(P) { | |
// 1. Let desc be the result of calling the [[GetOwnProperty]] internal | |
// method of O with argument P. | |
var desc = O.GetOwnProperty(P); | |
// 2. If desc is not undefined, then | |
if (desc !== undefined) { | |
// a. If IsAccessorDescriptor(desc) is true, then | |
if (IsAccessorDescriptor(desc)) { | |
// i. If desc.[[Set]] is undefined, then return false. | |
if (desc.set === undefined) { | |
return false; | |
} | |
// ii. Else return true. | |
else { | |
return true; | |
} | |
} | |
// b. Else, desc must be a DataDescriptor so return the value of | |
// desc.[[Writable]]. | |
else { | |
return desc.writable; | |
} | |
} | |
// 3. Let proto be the [[Prototype]] internal property of O. | |
var proto = O.__proto__; | |
// 4. If proto is null, then return the value of the [[Extensible]] internal | |
// property of O. | |
if (proto === null) { | |
return proto.Extensible; | |
} | |
// 5. Let inherited be the result of calling the [[GetProperty]] internal | |
// method of proto with property name P. | |
var inherited = proto.GetProperty(P); | |
// 6. If inherited is undefined, return the value of the [[Extensible]] | |
// internal property of O. | |
if (inherited === undefined) { | |
return O.Extensible; | |
} | |
// 7. If IsAccessorDescriptor(inherited) is true, then | |
if (IsAccessorDescriptor(inherited)) { | |
// a. If inherited.[[Set]] is undefined, then return false. | |
if (inherited.set === undefined) { | |
return false; | |
} | |
// b. Else return true. | |
else { | |
return true; | |
} | |
} | |
// 8. Else, inherited must be a DataDescriptor | |
else { | |
// a. If the [[Extensible]] internal property of O is false, return false. | |
if (O.Extensible === false) { | |
return false; | |
} | |
// b. Else return the value of inherited.[[Writable]]. | |
else { | |
return inherited.writable; | |
} | |
} | |
}; | |
// 8.12.5 [[Put]](P, V, Throw) | |
Object.prototype.Put = function(P, V, Throw) { | |
}; | |
// 8.12.6 [[HasProperty]](P) | |
Object.prototype.HasProperty = function(P) { | |
var O = this; | |
// 1. Let desc be the result of calling the [[GetProperty]] internal method | |
// of O with property name P. | |
var desc = O.GetProperty(P); | |
// 2. If desc is undefined, then return false. | |
if (desc === undefined) { | |
return false; | |
} | |
// 3. Else return true. | |
else { | |
return true; | |
} | |
}; | |
// 9.2 ToBoolean | |
var ToBoolean = function(arg) { | |
// ToBoolean Conversions | |
// +-------------+-------------------------------------------------------+ | |
// |Argument Type|Result | | |
// +=============+=======================================================+ | |
// |Undefined |false | | |
// +-------------+-------------------------------------------------------+ | |
// |Null |false | | |
// +-------------+-------------------------------------------------------+ | |
// |Boolean |The result equals the input argument (no conversion). | | |
// +-------------+-------------------------------------------------------+ | |
// |Number |The result is false if the argument is +0, -0, or NaN; | | |
// | |otherwise thr result is true. | | |
// +-------------+-------------------------------------------------------+ | |
// |String |The result is false if the argument is the empty String| | |
// | |(its length is zero); otherwise the result is true. | | |
// +-------------+-------------------------------------------------------+ | |
// |Object |true | | |
// +-------------+-------------------------------------------------------+ | |
if (arg == null) { | |
return false | |
} | |
switch (typeof arg) { | |
case "boolean": | |
return arg; | |
case "number": | |
return arg !== 0 && !isNaN(arg); | |
case "string": | |
return arg.length !== 0; | |
case "object": | |
return true; | |
} | |
}; | |
// 9.11 IsCallable | |
var IsCallable = function(arg) { | |
// IsCallable Results | |
// +-------------+-------------------------------------------------------+ | |
// |Argument Type|Result | | |
// +=============+=======================================================+ | |
// |Undefined |Return false. | | |
// +-------------+-------------------------------------------------------+ | |
// |Null |Return false. | | |
// +-------------+-------------------------------------------------------+ | |
// |Boolean |Return false. | | |
// +-------------+-------------------------------------------------------+ | |
// |Number |Return false. | | |
// +-------------+-------------------------------------------------------+ | |
// |String |Return false. | | |
// +-------------+-------------------------------------------------------+ | |
// |Object |If the argument object has a [[Call]] internal method, | | |
// | |then return true, otherwise return false. | | |
// +-------------+-------------------------------------------------------+ | |
if (typeof arg !== "object") { | |
return false; | |
} | |
return typeof arg.call === "function"; | |
}; | |
// 15.2.3.2 Object.getPrototypeOf(O) | |
Object.getPrototypeOf = function (O) { | |
// 1. If Type(O) is not Object, throw a TypeError exception. | |
if (typeof O !== "object") { | |
throw TypeError("Object.getPrototypeOf called on non-object"); | |
} | |
// 2. Return the value of the [[Prototype]] internal property of O | |
return O.__proto__; | |
}; | |
// 15.2.3.3 Object.getOwnPropertyDescriptor(O, P) | |
Object.getOwnPropertyDescriptor = function(O, P) { | |
// 1. If Type(O) is not Object throw a TypeError exception. | |
if (typeof O !== "object") { | |
throw TypeError("Object.getOwnPropertyDescriptor called on non-object"); | |
} | |
// 2. Let name be ToString(P). | |
var name = P.toString(); | |
// 3. Let desc be the result of calling the [[GetOwnProperty]] internal | |
// method of O with argument name. | |
var desc = O.GetOwnProperty(name); | |
// 4. Return the result of calling FromPropertyDescriptor(desc) (8.10.4). | |
return FromPropertyDescriptor(desc); | |
}; | |
// 15.2.3.5 Object.create(O[, Properties]) | |
// | |
// The create function creates a new object with a specifed prototype. | |
Object.create = function (O, Properties) { | |
// 1. If Type(O) is not Object or Null, throw a TypeError exception. | |
if (typeof O !== "object" || O === null) { | |
throw TypeError("Object prototype may only be an Object or null"); | |
} | |
// 2. Let obj be the result of creating a new object as if by the expression | |
// new Object() where Object is the standard built-in constructor with | |
// that name. | |
var obj = new Object(); | |
// 3. Set the [[Prototype]] internal property of obj to O | |
obj.__proto__ = O; | |
// 4. If the argument Properties is present and not undefined, add own | |
// properties to obj as if by calling the standard built-in function | |
// Object.defineProperties with arguments obj and Properties. | |
if (Properties !== undefined) { | |
Object.defineProperties(obj, Properties); | |
} | |
// 5. Return obj. | |
return obj | |
}; | |
// 15.2.3.14 Object.keys(O) | |
Object.keys = function (O) { | |
if (typeof O !== "object") { | |
throw TypeError("Object.keys called on non-object"); | |
} | |
var array = [], index = 0; | |
for (var P in O) { | |
if (O.hasOwnProperty(P)) { | |
Object.defineProperty(array, index, { | |
value: P, writable: true, enumerable: true, configurable: true | |
}); | |
index++; | |
} | |
} | |
return array; | |
}; | |
// 15.2.4.6 Object.prototype.isPrototypeOf(V) | |
Object.prototype.isPrototypeOf = function (V) { | |
if (typeof V !== "object") { return false } | |
while (V = Object.getPrototypeOf(V)) { | |
if (V === null) { | |
return false | |
} else if (this === V) { | |
return true | |
} | |
} | |
}; | |
// 15.4.3.2 Array.isArray(arg) | |
Array.isArray = function (arg) { | |
return arg.constructor.name === "Array" | |
}; | |
// 15.4.4.14 Array.prototype.indexOf(searchElement[, fromIndex]) | |
Array.prototype.indexOf = function (searchElement, fromIndex) { | |
if (this.length == 0) { return -1 } | |
fromIndex = 0 + fromIndex || 0; | |
if (fromIndex >= this.length) { return -1 } | |
var k; | |
if (fromIndex >= 0) { | |
k = fromIndex; | |
} else { | |
k = Math.max(len - Math.abs(fromIndex), 0); | |
} | |
for (; k < this.length; k++) { | |
if (this[k] === searchElement) { | |
return k | |
} | |
} | |
} | |
return -1 | |
}; | |
// 15.4.4.15 Array.prototype.lastIndexOf(searchElement[, fromIndex]) | |
Array.prototype.lastIndexOf = function (searchElement, fromIndex) { | |
if (this.length == 0) { return -1 } | |
fromIndex = 0 + fromIndex || this.len - 1; | |
var k; | |
if (fromIndex >= 0) { | |
k = Math.min(fromIndex, this.length - 1); | |
} else { | |
k = this.length - Math.abs(fromIndex); | |
} | |
for (; k >= 0; k--) { | |
if (this[k] === searchElement) { | |
return k | |
} | |
} | |
return -1 | |
}; | |
// 15.4.4.16 Array.prototype.every(callbackfn[, thisArg]) | |
Array.prototype.every = function (callbackfn, thisArg) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} | |
for (var k = 0; k < this.length; k++) { | |
if (!callbackfn.call(thisArg, this[k])) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
// 15.4.4.17 Array.prototype.some(callbackfn[, thisArg]) | |
Array.prototype.some = function (callbackfn, thisArg) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} | |
for (var k = 0; k < this.length; k++) { | |
if (callbackfn.call(thisArg, this[k])) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
// 15.4.4.18 Array.prototype.forEach(callbackfn[, thisArg]) | |
Array.prototype.forEach = function (callbackfn, thisArg) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} | |
for (var k = 0; k < this.length; k++) { | |
callbackfn.call(thisArg, this[k]); | |
} | |
}; | |
// 15.4.4.19 Array.prototype.map(callbackfn[, thisArg]) | |
Array.prototype.map = function (callbackfn, thisArg) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} | |
var a = []; | |
for (var k = 0; k < this.length; k++) { | |
a.push(callbackfn.call(thisArg, this[k])); | |
} | |
return a; | |
}; | |
// 15.4.4.20 Array.prototype.filter(callbackfn[, thisArg]) | |
Array.prototype.filter = function (callbackfn, thisArg) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} | |
var a = [], r; | |
for (var k = 0; k < this.length; k++) { | |
if (r = callbackfn.call(thisArg, this[k])) { | |
a.push(r); | |
} | |
} | |
return a; | |
}; | |
// 15.4.4.21 Array.prototype.reduce(callbackfn[, initialValue]) | |
Array.prototype.reduce = function (callbackfn, initialValue) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} else if (this.length === 0 && initialValue === undefined) { | |
throw TypeError("Reduce of empty array with no initial value"); | |
} | |
var accumulator, k; | |
if (initialValue) { | |
accumulator = initialValue; | |
k = 0; | |
} else { | |
accumulator = this[0]; | |
k = 1; | |
} | |
for (; k < this.length; k++) { | |
accumulator = callbackfn.call(undefined, accumulator, this[k], k, this); | |
} | |
return accumulator | |
}; | |
// 15.4.4.22 Array.prototype.reduceRight(callbackfn[, initialValue]) | |
Array.prototype.reduceRight = function (callbackfn, initialValue) { | |
if (typeof callbackfn !== "function") { | |
throw TypeError("" + callbackfn + " is not a function"); | |
} else if (this.length === 0 && initialValue === undefined) { | |
throw TypeError("Reduce of empty array with no initial value"); | |
} | |
var accumulator, k; | |
if (initialValue) { | |
accumulator = initialValue; | |
k = this.length - 1; | |
} else { | |
accumulator = this[this.length - 1]; | |
k = this.lengh - 2; | |
} | |
for (; k >= 0; k-- { | |
accumulator = callbackfn.call(undefined, accumulator, this[k], k, this); | |
} | |
return accumulator | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment