UNPKG

bugcore

Version:

bugcore is a JavaScript library that provides a foundational architecture for object oriented JS

302 lines (251 loc) 9.4 kB
/* * Copyright (c) 2016 airbug Inc. http://airbug.com * * bugcore may be freely distributed under the MIT license. */ //------------------------------------------------------------------------------- // Annotations //------------------------------------------------------------------------------- //@Export('Obj') //@Require('Class') //@Require('HashUtil') //@Require('IClone') //@Require('IEquals') //@Require('IHashCode') //@Require('IdGenerator') //@Require('ObjectUtil') //@Require('TypeUtil') //------------------------------------------------------------------------------- // Context //------------------------------------------------------------------------------- require('bugpack').context("*", function(bugpack) { //------------------------------------------------------------------------------- // BugPack //------------------------------------------------------------------------------- var Class = bugpack.require('Class'); var HashUtil = bugpack.require('HashUtil'); var IClone = bugpack.require('IClone'); var IEquals = bugpack.require('IEquals'); var IHashCode = bugpack.require('IHashCode'); var IdGenerator = bugpack.require('IdGenerator'); var ObjectUtil = bugpack.require('ObjectUtil'); var TypeUtil = bugpack.require('TypeUtil'); //------------------------------------------------------------------------------- // Declare Class //------------------------------------------------------------------------------- /** * @class * @extends {Constructor} * @implements {IClone} * @implements {IEquals} * @implements {IHashCode} */ var Obj = Class.declare(/** @lends {Obj.prototype} */{ _name: "Obj", //------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------- /** * @constructs */ _constructor: function() { //------------------------------------------------------------------------------- // Private Properties //------------------------------------------------------------------------------- /** * @private * @type {?number} */ this._hashCode = null; // NOTE BRN: This value is set during the call to IdGenerator.ensureId(). We just put this here for clarity's sake. /** * @private * @type {?number} */ this._internalId = null; ObjectUtil.defineProperty(this, "_hashCode", { value : null, writable : true, enumerable : false, configurable : false }); }, //------------------------------------------------------------------------------- // Init Methods //------------------------------------------------------------------------------- /** * @return {Obj} */ init: function() { this.generateInternalId(); return this; }, //------------------------------------------------------------------------------- // Getters and Setters //------------------------------------------------------------------------------- /** * @return {number} */ getInternalId: function() { return this._internalId; }, //------------------------------------------------------------------------------- // IClone Implementation //------------------------------------------------------------------------------- /** * @param {boolean=} deep * @return {*} */ clone: function(deep) { var _class = this.getClass(); var constructor = _class.getConstructor(); var cloneObject = new constructor(); ObjectUtil.forIn(this, function(key, value) { if (!TypeUtil.isFunction(value)) { if (deep) { cloneObject[key] = Obj.clone(value, deep); } else { cloneObject[key] = value; } } }); return cloneObject; }, //------------------------------------------------------------------------------- // IEquals Implementation //------------------------------------------------------------------------------- /** * If two Objs are equal then they MUST return the same hashCode. Otherwise the world will end! * @param {*} value * @return {boolean} */ equals: function(value) { if (value !== null && value !== undefined) { return (value._internalId === this._internalId); } return false; }, //------------------------------------------------------------------------------- // IHashCode Implementation //------------------------------------------------------------------------------- /** * Equal hash codes do not necessarily guarantee equality. * @return {number} */ hashCode: function() { if (!this._hashCode) { this._hashCode = HashUtil.hash(this); } return this._hashCode; }, //------------------------------------------------------------------------------- // Protected Methods //------------------------------------------------------------------------------- /** * @protected */ generateInternalId: function() { IdGenerator.ensureId(this); } }); //------------------------------------------------------------------------------- // Interfaces //------------------------------------------------------------------------------- Class.implement(Obj, IClone); Class.implement(Obj, IEquals); Class.implement(Obj, IHashCode); //------------------------------------------------------------------------------- // Static Public Methods //------------------------------------------------------------------------------- /** * @static * @param {A} value * @param {boolean=} deep * @return {A} * @template A */ Obj.clone = function(value, deep) { var clone = null; if (TypeUtil.isDate(value)) { clone = new Date(); clone.setTime(value.getTime()); } else if (TypeUtil.isObject(value)) { if (Class.doesImplement(value, IClone)) { clone = value.clone(deep); } else { clone = {}; ObjectUtil.forIn(value, function(propertyName, propertyValue) { if (deep) { clone[propertyName] = Obj.clone(propertyValue, deep); } else { clone[propertyName] = propertyValue; } }); } } else if (TypeUtil.isArray(value)) { clone = []; for (var i = 0, size = value.length; i < size; i++) { var arrayValue = value[i]; if (deep) { clone.push(Obj.clone(arrayValue, deep)); } else { clone.push(arrayValue); } } } else { //TODO BRN: Any other basic types that need to be cloned? clone = value; } return clone; }; /** * @static * @param {*} value1 * @param {*} value2 * @return {boolean} */ Obj.equals = function(value1, value2) { if (Class.doesImplement(value1, IEquals)) { return value1.equals(value2); } var type1 = TypeUtil.toType(value1); var type2 = TypeUtil.toType(value2); if (type1 === type2) { switch (type1) { case "boolean": value1 = value1.valueOf(); value2 = value2.valueOf(); break; case "date": value1 = value1.getTime(); value2 = value2.getTime(); break; case "number": value1 = value1 - 0; value2 = value2 - 0; break; case "string": value1 = value1 + ""; value2 = value2 + ""; break; } } return value1 === value2; }; /** * @static * @param {*} value * @return {number} */ Obj.hashCode = function(value) { if (Class.doesImplement(value, IHashCode)) { return value.hashCode(); } else { return HashUtil.hash(value); } }; //------------------------------------------------------------------------------- // Exports //------------------------------------------------------------------------------- bugpack.export('Obj', Obj); });