prototype/src/lang/object.js

291 lines
8.6 KiB
JavaScript

/** section: Language
* class Object
*
* Extensions to the built-in `Object` object.
*
* Because it is dangerous and invasive to augment `Object.prototype` (i.e.,
* add instance methods to objects), all these methods are static methods that
* take an `Object` as their first parameter.
*
**/
(function() {
var _toString = Object.prototype.toString;
/**
* Object.extend(destination, source) -> Object
* - destination (Object): The object to receive the new properties.
* - source (Object): The object whose properties will be duplicated.
*
* Copies all properties from the source to the destination object. Returns
* the destination object.
**/
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
/**
* Object.inspect(object) -> String
* - object (Object): The item to be inspected.
*
* Returns the debug-oriented string representation of the object.
*
* `undefined` and `null` are represented as such.
*
* Other types are checked for a `inspect` method. If there is one, it is
* used; otherwise, it reverts to the `toString` method.
*
* Prototype provides `inspect` methods for many types, both built-in and
* library-defined — among them `String`, `Array`, `Enumerable` and `Hash`.
* These attempt to provide useful string representations (from a
* developer's standpoint) for their respective types.
**/
function inspect(object) {
try {
if (isUndefined(object)) return 'undefined';
if (object === null) return 'null';
return object.inspect ? object.inspect() : String(object);
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
}
}
/**
* Object.toJSON(object) -> String
* - object (Object): The object to be serialized.
*
* Returns a JSON string.
*
* `undefined` and `function` types have no JSON representation. `boolean`
* and `null` are coerced to strings.
*
* For other types, `Object.toJSON` looks for a `toJSON` method on `object`.
* If there is one, it is used; otherwise the object is treated like a
* generic `Object`.
**/
function toJSON(object) {
var type = typeof object;
switch (type) {
case 'undefined':
case 'function':
case 'unknown': return;
case 'boolean': return object.toString();
}
if (object === null) return 'null';
if (object.toJSON) return object.toJSON();
if (isElement(object)) return;
var results = [];
for (var property in object) {
var value = toJSON(object[property]);
if (!isUndefined(value))
results.push(property.toJSON() + ': ' + value);
}
return '{' + results.join(', ') + '}';
}
/**
* Object.toQueryString(object) -> String
* object (Object): The object whose property/value pairs will be converted.
*
* Turns an object into its URL-encoded query string representation.
*
* This is a form of serialization, and is mostly useful to provide complex
* parameter sets for stuff such as objects in the Ajax namespace (e.g.
* [[Ajax.Request]]).
*
* Undefined-value pairs will be serialized as if empty-valued. Array-valued
* pairs will get serialized with one name/value pair per array element. All
* values get URI-encoded using JavaScript's native `encodeURIComponent`
* function.
*
* The order of pairs in the serialized form is not guaranteed (and mostly
* irrelevant anyway) — except for array-based parts, which are serialized
* in array order.
**/
function toQueryString(object) {
return $H(object).toQueryString();
}
/**
* Object.toHTML(object) -> String
* - object (Object): The object to convert to HTML.
*
* Converts the object to its HTML representation.
*
* Returns the return value of `object`'s `toHTML` method if it exists; else
* runs `object` through [[String.interpret]].
**/
function toHTML(object) {
return object && object.toHTML ? object.toHTML() : String.interpret(object);
}
/**
* Object.keys(object) -> Array
* - object (Object): The object to pull keys from.
*
* Returns an array of the object's property names.
*
* Note that the order of the resulting array is browser-dependent — it
* relies on the `for…in` loop, for which the ECMAScript spec does not
* prescribe an enumeration order. Sort the resulting array if you wish to
* normalize the order of the object keys.
**/
function keys(object) {
var results = [];
for (var property in object)
results.push(property);
return results;
}
/**
* Object.values(object) -> Array
* - object (Object): The object to pull values from.
*
* Returns an array of the object's values.
*
* Note that the order of the resulting array is browser-dependent — it
* relies on the `for…in` loop, for which the ECMAScript spec does not
* prescribe an enumeration order.
*
* Also, remember that while property _names_ are unique, property _values_
* have no such constraint.
**/
function values(object) {
var results = [];
for (var property in object)
results.push(object[property]);
return results;
}
/**
* Object.clone(object) -> Object
* - object (Object): The object to clone.
*
* Creates and returns a shallow duplicate of the passed object by copying
* all of the original's key/value pairs onto an empty object.
*
* Do note that this is a _shallow_ copy, not a _deep_ copy. Nested objects
* will retain their references.
*
* <h5>Examples</h5>
*
* var original = {name: 'primaryColors', values: ['red', 'green', 'blue']};
* var copy = Object.clone(original);
* original.name;
* // -> "primaryColors"
* original.values[0];
* // -> "red"
* copy.name;
* // -> "primaryColors"
* copy.name = "secondaryColors";
* original.name;
* // -> "primaryColors"
* copy.name;
* // -> "secondaryColors"
* copy.values[0] = 'magenta';
* copy.values[1] = 'cyan';
* copy.values[2] = 'yellow';
* original.values[0];
* // -> "magenta" (it was a shallow copy, so they shared the array)
**/
function clone(object) {
return extend({ }, object);
}
/**
* Object.isElement(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is a DOM node of type 1; `false` otherwise.
**/
function isElement(object) {
return !!(object && object.nodeType == 1);
}
/**
* Object.isArray(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is an array; false otherwise.
**/
function isArray(object) {
return _toString.call(object) == "[object Array]";
}
/**
* Object.isHash(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is an instance of the [[Hash]] class; `false`
* otherwise.
**/
function isHash(object) {
return object instanceof Hash;
}
/**
* Object.isFunction(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is of type `function`; `false` otherwise.
**/
function isFunction(object) {
return typeof object === "function";
}
/**
* Object.isString(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is of type `string`; `false` otherwise.
**/
function isString(object) {
return _toString.call(object) == "[object String]";
}
/**
* Object.isNumber(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is of type `number`; `false` otherwise.
**/
function isNumber(object) {
return _toString.call(object) == "[object Number]";
}
/**
* Object.isUndefined(object) -> Boolean
* - object (Object): The object to test.
*
* Returns `true` if `object` is of type `string`; `false` otherwise.
**/
function isUndefined(object) {
return typeof object === "undefined";
}
extend(Object, {
extend: extend,
inspect: inspect,
toJSON: toJSON,
toQueryString: toQueryString,
toHTML: toHTML,
keys: keys,
values: values,
clone: clone,
isElement: isElement,
isArray: isArray,
isHash: isHash,
isFunction: isFunction,
isString: isString,
isNumber: isNumber,
isUndefined: isUndefined
});
})();