Created
August 16, 2011 04:14
-
-
Save draeton/1148428 to your computer and use it in GitHub Desktop.
extend objects or functions from right to left with properties from other objects
This file contains 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
(function () { | |
var toString = Object.prototype.toString, | |
slice = Array.prototype.slice, | |
/** | |
* determines type of passed argument | |
*/ | |
toType = function (thing) { | |
return toString.call(thing).match(/\s(\w+)/)[1].toLowerCase(); | |
}, | |
/** | |
* toType curry | |
*/ | |
is = function (type) { | |
return function (thing) { | |
return toType(thing) === type; | |
}; | |
}, | |
/** | |
* is this an instance of the Object prototype or its descendants | |
*/ | |
isObject = function (thing) { | |
return thing instanceof Object; | |
}, | |
/** | |
* toType shortcuts | |
*/ | |
isPlainObject = is('object'), | |
isFunction = is('function'), | |
isArray = is('array'), | |
isNumber = is('number'), | |
isBoolean = is('boolean'); | |
/** | |
* extend objects or functions from right to left with properties from other | |
* objects, and return the first extended argument; used for applying options | |
* to defaults, or extending classes or constructors | |
* @return {Object|Function} | |
*/ | |
Object.extend = function () { | |
var args = slice.call(arguments), // convert arguments object to Array | |
ret = null, | |
o = null, | |
cur = null, | |
i = null, | |
j = null, | |
deep = false, | |
stack = []; | |
// if the first arg is boolean, it determines if we are deep copying objects | |
// if it is boolean, remove it from args for further processing of args | |
if (isBoolean(args[0])) { | |
deep = args.shift(); | |
} | |
// push the remaining arguments onto the stack | |
stack.push(args); | |
// the return value object will be the first remaining argument | |
ret = args[0]; | |
// only allow processing of objects, and the remaining | |
// args length must be greater than 1 to have something to copy | |
if (isObject(ret) && args.length > 1) { | |
// get the next item from stack and set as args | |
// args is an array of objects | |
while (args = stack.shift()) { | |
// o is the item we are copying all values into | |
o = args.shift(); | |
// get the next item from args and set as cur | |
// cur is an object | |
while (cur = args.shift()) { | |
// check for objects only | |
if (!(isObject(cur))) { | |
throw new TypeError("Argument must be an object"); | |
} else { | |
// loop through properties i | |
// if cur has own property i, proceed | |
for (i in cur) { | |
if (cur.hasOwnProperty(i)) { | |
// if this is a deep copy, and o[i] & cur[i] are objects | |
// add o[i] and cur[i] to the stack to override | |
// properties instead of replacing the whole object | |
if (deep && isObject(o[i]) && isObject(cur[i])) { | |
stack.push([o[i], cur[i]]); | |
} else { | |
// if cur[i] is an object, clone and replace o[i] | |
// else, set o[i] to cur[i] | |
if (isObject(cur[i])) { | |
if (!isObject(o[i])) { | |
o[i] = {}; | |
} | |
stack.push([o[i], cur[i]]); | |
} else { | |
o[i] = cur[i]; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
return ret; | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment