Skip to content

Instantly share code, notes, and snippets.

@Skateside
Created July 29, 2012 22:06
Show Gist options
  • Save Skateside/3202105 to your computer and use it in GitHub Desktop.
Save Skateside/3202105 to your computer and use it in GitHub Desktop.
I've been looking at Sugar and RightJS and I figured I'd start playing with my own version. I like what these things do to the language, they make it seem a lot more sensible. Ultimately this would add the ES5 and ES6 methods as well as some more new ones
// This is very similar to the standard implimentation of Object.extend but the
// important difference here is that this method will not overwrite any existing
// method of the source object. This makes it idea for updating native objects.
if (!Object.hasOwnProperty('update')) {
(function () {
'use strict';
var setProp = function (source, property, value) {
Object.defineProperty(source, property, {
value: value,
enumarable: false
});
};
function definePropertyWorks() {
var obj = {},
works = false;
try {
Object.defineProperty(obj, 'sk80', {});
works = obj.hasOwnProperty('sk80');
} catch (e) {
}
return works;
}
if (!definePropertyWorks()) {
setProp = function (source, property, value) {
source[property] = value;
};
}
Object.update = function (source, update) {
var property;
for (property in update) {
if (update.hasOwnProperty(property)
&& !source.hasOwnProperty(property)) {
setProp(source, property, update[property]);
}
}
return source;
};
}());
}
Object.update(Number.prototype, (function () {
'use strict';
var undef,
// These bizare-looking variable statements allows us to minify some of the
// global variables that we use in this function.
Math = window.Math,
isFinite = window.isFinite;
// Extends an object with another object. Each key in the object is checked to
// make sure that it does not exist in the source object before it is added.
//
// Takes:
// source {Object} The source Object to extend.
// extra {Object} The extra keys to add to the source.
//
// Returns:
// {Object} The extended Object.
function extend(source, extra) {
var i;
for (i in extra) {
if (extra.hasOwnProperty(i) && !source.hasOwnProperty(i)) {
source[i] = extra[i];
}
}
return source;
}
// Creates an absolute value of a given number. Since it converts a number using
// parseInt, this function will also work with numeric strings.
//
// Takes:
// number {Mixed} Hopefully either a Number or a numeric String.
//
// Returns:
// {Number} An absolute value of the given number, or NaN if
// number was not numeric.
function absNumber(number) {
return parseInt(number).abs();
}
// A few places in the ECMAScript specifications says:
// "Let posInt be sign(number) * floor(abs(number))"
// Since it's used a few times, we may as well make a function to aid
// minification and prevent us repeating ourselves.
// I know it has the potential to return a negative integer, that's always
// bugged me about the specs.
//
// Takes:
// number {Number} The number to convert into a positive integer.
//
// Returns:
// {Number} The positive integer, or NaN if number was not
// numeric.
function posInt(number) {
return number.sign() * number.abs().floor();
}
return {
// A simple mapping of Math.pow.
pow: function (power) {
return Math.pow(this, power);
},
// A simple mapping of Math.abs.
abs: function () {
return Math.abs(this);
},
// We map Math.floor, Math.ceil and Math.round to Number.prototype and add the
// ability to define a precision. These are all based on functions written by
// Lea Verou.
// http://lea.verou.me/2009/02/extend-mathround-mathceil-and-mathfloor-to-allow-precision/
floor: function (precision) {
var p = absNumber(precision) || 0,
coefficient = (10).pow(p);
return Math.floor(this * coefficient) / coefficient;
},
ceil: function (precision) {
var p = absNumber(precision) || 0,
coefficient = (10).pow(p);
return Math.ceil(this * coefficient) / coefficient;
},
round: function (precision) {
var p = absNumber(precision) || 0,
coefficient = (10).pow(p);
return Math.round(this * coefficient) / coefficient;
},
// http://es5.github.com/#sign
sign: function () {
var number = +this;
if (!isNaN(number)) {
number = number < 0 ? -1 : 1;
}
return number;
},
// http://es5.github.com/#x9.4
toInt: function () {
var number = +this,
ret = 0;
if (!isNaN(number)) {
if (number === 0 || !isFinite(number)) {
ret = number;
} else {
ret = posInt(number);
}
}
return ret;
},
// http://es5.github.com/#x9.5
toInt32: function () {
var number = +this,
ret = 0,
two = 2,
twoPow32 = two.pow(32);
if (!isNaN(number) && isFinite(number)) {
ret = posInt(number) % twoPow32;
if (ret >= two.pow(31)) {
ret -= twoPow32;
}
}
return ret;
},
// http://es5.github.com/#x9.6
toUint32: function () {
var number = +this,
ret = 0;
if (!isNaN(number) && isFinite(number)) {
ret = posInt(number) % (2).pow(32);
}
return ret;
},
// http://sk80.co.uk/2012/04/number-prototype-times/
times: function (func, thisArg) {
var i = 0,
t = posInt(this).abs();
if (Object.prototype.toString.call(func) !== '[object Function]') {
throw new TypeError(func + ' is not a function');
}
while (i < t) {
func.call(thisArg, i);
i += 1;
}
return t;
}
};
}()));
Object.update(Array.prototype, (function () {
'use strict';
var undef,
toString = Object.prototype.toString,
isStringArray = 'a'[0] === 'a';
// Converts an object into its primative type, throws errors if it's given null
// or undefined.
// http://es5.github.com/#x9.9
function toObject(o) {
if (o === undef || o === null) {
throw new TypeError('can\'t convert null or undefined to object');
}
if (!isStringArray && toString.call(o) === '[object String]') {
o = o.split('');
}
return Object(o);
}
return {
remove: function (entry) {
var array = toObject(this),
index = array.indexOf(entry);
if (index > -1) {
array.splice(index, 1);
}
return array;
},
insert: function (first, array, second) {
var keyArray = toObject(this),
boundArray = toObject(array),
index = keyArray.push(first) - 1;
boundArray[index] = second;
return keyArray;
},
// If only "delete" weren't a key word.
uninsert: function (entry, array) {
var keyArray = toObject(this),
boundArray = toObject(array),
index = keyArray.indexOf(entry);
if (index > -1) {
keyArray.splice(index, 1);
boundArray.splice(index, 1);
}
return keyArray;
}
};
}()));
Object.update(Function.prototype, (function () {
'use strict';
// These two Arrays are bound, the indices should match. As a function is pushed
// into the functions array, an Array containing true or false and the delayed
// function is put into the timers array at the same index.
var functions = [],
timers = [];
function checkFunction(func) {
if (Object.prototype.toString.call(func) !== '[object Function]') {
throw new TypeError(func + ' is not a function');
}
}
return {
delay: function (milliseconds) {
checkFunction(this);
functions
.insert(this, timers, [true, setTimeout(this, milliseconds)]);
return this;
},
repeat: function (milliseconds) {
checkFunction(this);
functions
.insert(this, timers, [false, setInterval(this, milliseconds)]);
return this;
},
stop: function () {
var index = functions.indexOf(this),
timer;
checkFunction(this);
if (index > -1) {
timer = timers[index];
if (timer[0]) {
clearTimeout(timer[1]);
} else {
clearInterval(timer[1]);
}
functions.uninsert(this, timers);
}
return this;
}
};
}()));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment