neuronjs
Version:
Neuron is A Full Feature CommonJS Module Manager, Dependency Graph Handler and Loader for Browsers
333 lines (254 loc) • 7.44 kB
JavaScript
// ## ECMAScript5 implementation
//////////////////////////////////////////////////////////////////////
// - methods native object implemented
// - methods native object extends
// codes from mootools, MDC or by Kael Zhang
// ## Indexes
// ### Array.prototype
// - indexOf
// - lastIndexOf
// - filter
// - forEach
// - every
// - map
// - some
// - reduce
// - reduceRight
// ### Object
// - keys
// - create: removed
// ### String.prototype
// - trim
// - trimLeft
// - trimRight
// ## Specification
// ### STANDALONE language enhancement
// - always has no dependencies on Neuron
// - always follow ECMA standard strictly, including logic, exception type
// - throw the same error hint as webkit on a certain exception
function extend(host, methods) {
for (var name in methods) {
if (!host[name]) {
host[name] = methods[name];
}
}
}
function implement(host, methods) {
extend(host.prototype, methods);
}
var TYPE_ERROR = TypeError;
// ref: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
implement(Array, {
// Accessor methods ------------------------
indexOf: function(value, from) {
var len = this.length >>> 0;
from = Number(from) || 0;
from = Math[from < 0 ? 'ceil' : 'floor'](from);
if (from < 0) {
from = Math.max(from + len, 0);
}
for (; from < len; from++) {
if (from in this && this[from] === value) {
return from;
}
}
return -1;
},
lastIndexOf: function(value, from) {
var len = this.length >>> 0;
from = Number(from) || len - 1;
from = Math[from < 0 ? 'ceil' : 'floor'](from);
if (from < 0) {
from += len;
}
from = Math.min(from, len - 1);
for (; from >= 0; from--) {
if (from in this && this[from] === value) {
return from;
}
}
return -1;
},
// Iteration methods -----------------------
filter: function(fn, thisObject) {
var ret = [];
for (var i = 0, len = this.length; i < len; i++) {
// Kael:
// Some people might ask: "why we use a `i in this` here?".
// ECMA:
// > callback is invoked only for indexes of the array which have assigned values;
// > it is not invoked for indexes which have been deleted or which have never been assigned values
// Besides, `filter` method is not always used with real Arrays, invocations below might happen:
// var obj = {length: 4}; obj[3] = 1;
// Array.prototype.filter.call({length: 4});
// Array.prototype.filter.call($('body'));
// as well as the lines below
if ((i in this) && fn.call(thisObject, this[i], i, this)) {
ret.push(this[i]);
}
}
return ret;
},
forEach: function(fn, thisObject) {
for (var i = 0, len = this.length; i < len; i++) {
if (i in this) {
// if fn is not callable, it will throw
fn.call(thisObject, this[i], i, this);
}
}
},
every: function(fn, thisObject) {
for (var i = 0, len = this.length; i < len; i++) {
if ((i in this) && !fn.call(thisObject, this[i], i, this)) {
return false;
}
}
return true;
},
map: function(fn, thisObject) {
var ret = [],
i = 0,
l = this.length;
for (; i < l; i++) {
// if the subject of the index i is deleted, index i should not be contained in the result of array.map()
if (i in this) {
ret[i] = fn.call(thisObject, this[i], i, this);
}
}
return ret;
},
some: function(fn, thisObject) {
for (var i = 0, l = this.length; i < l; i++) {
if ((i in this) && fn.call(thisObject, this[i], i, this)) {
return true;
}
}
return false;
},
reduce: function(fn) {
if (typeof fn !== 'function') {
throw new TYPE_ERROR(fn + ' is not an function');
}
var self = this,
len = self.length >>> 0,
i = 0,
ret;
if (arguments.length > 1) {
ret = arguments[1];
} else {
do {
if (i in self) {
ret = self[i++];
break;
}
// if array contains no values, no initial value to return
if (++i >= len) {
throw new TYPE_ERROR('Reduce of empty array with on initial value');
}
} while (true);
}
for (; i < len; i++) {
if (i in self) {
ret = fn.call(NULL, ret, self[i], i, self);
}
}
return ret;
},
reduceRight: function(fn) {
if (typeof fn !== 'function') {
throw new TYPE_ERROR(fn + ' is not an function');
}
var self = this,
len = self.length >>> 0,
i = len - 1,
ret;
if (arguments.length > 1) {
ret = arguments[1];
} else {
do {
if (i in self) {
ret = self[i--];
break;
}
// if array contains no values, no initial value to return
if (--i < 0) {
throw new TYPE_ERROR('Reduce of empty array with on initial value');
}
} while (true);
}
for (; i >= 0; i--) {
if (i in self) {
ret = fn.call(NULL, ret, self[i], i, self);
}
}
return ret;
}
});
extend(Object, {
// ~ https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create ~
// create: function(o){
// if(o !== Object(o) && o !== NULL){
// throw new TYPE_ERROR('Object prototype may only be an Object or NULL');
// }
// function F() {}
// F.prototype = o;
// return new F();
// },
// refs:
// http://ejohn.org/blog/ecmascript-5-objects-and-properties/
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
// https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute
// http://msdn.microsoft.com/en-us/library/adebfyya(v=vs.94).aspx
keys: (function() {
var hasOwnProperty = Object.prototype.hasOwnProperty,
has_dontEnumBug = !{
toString: ''
}.propertyIsEnumerable('toString'),
// In some old browsers, such as OLD IE, keys below might not be able to iterated with `for-in`,
// even if each of them is one of current object's own properties
NONT_ENUMS = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
NONT_ENUMS_LENGTH = NONT_ENUMS.length;
return function(o) {
if (o !== Object(o)) {
throw new TYPE_ERROR('Object.keys called on non-object');
}
var ret = [],
name;
for (name in o) {
if (hasOwnProperty.call(o, name)) {
ret.push(name);
}
}
if (has_dontEnumBug) {
for (var i = 0; i < NONT_ENUMS_LENGTH; i++) {
if (hasOwnProperty.call(o, NONT_ENUMS[i])) {
ret.push(NONT_ENUMS[i]);
}
}
}
return ret;
};
})()
// for our current OOP pattern, we don't reply on Object based inheritance
// so Neuron has not implemented the methods of Object such as Object.defineProperty, etc.
});
implement(String, {
trimLeft: function() {
return this.replace(/^\s+/, '');
},
trimRight: function() {
return this.replace(/\s+$/, '');
},
trim: function() {
return this.trimLeft().trimRight();
}
});