lib/dot/object.jst
'use strict';
{{# def.definitions }}
{{# def.keys }}
/**
* - [extend](#extend)
* - [clone](#clone)
* - [defineProperty](#defineProperty)
* - [defineProperties](#defineProperties)
* - [deepExtend](#deepExtend)
* - [deepClone](#deepClone)
* - [keys](#keys)
* - [allKeys](#allKeys)
* - [values](#values)
* - [keyOf](#keyOf)
* - [allKeysOf](#allKeysOf)
* - [eachKey](#eachKey)
* - [mapKeys](#mapKeys)
* - [reduceKeys](#reduceKeys)
* - [filterKeys](#filterKeys)
* - [someKey](#someKey)
* - [everyKey](#everyKey)
* - [findValue](#findValue)
* - [findKey](#findKey)
* - [pickKeys](#pickKeys)
* - [omitKeys](#omitKeys)
* - [isEqual](#isEqual)
* - [isNot](#isNot)
*
* All these methods can be [chained](proto.js.html#Proto)
*/
module.exports = {
extend: extend,
clone: clone,
findValue: findValue,
findKey: findKey,
defineProperty: defineProperty,
defineProperties: defineProperties,
deepExtend: deepExtend,
deepClone: deepClone,
keys: keys,
allKeys: allKeys,
values: values,
keyOf: keyOf,
allKeysOf: allKeysOf,
eachKey: eachKey,
mapKeys: mapKeys,
reduceKeys: reduceKeys,
filterKeys: filterKeys,
someKey: someKey,
everyKey: everyKey,
pickKeys: pickKeys,
omitKeys: omitKeys,
isEqual: isEqual,
isNot: isNot
};
var concat = Array.prototype.concat;
/**
* ####Property descriptor constants####
* The sum of these constants can be used as last parameter of defineProperty and defineProperties to determine types of properties.
*/
var constants = module.exports._constants = {
ENUMERABLE: 1,
ENUM: 1,
CONFIGURABLE: 2,
CONF: 2,
WRITABLE: 4,
WRIT: 4
};
/**
* Extends object `self` with the properties of the object `obj` copying all own properties (not those inherited via prototype chain), including non-enumerable properties (unless `onlyEnumerable` is truthy).
* Created properties will have the same descriptors as the propertis of `obj`.
* Returns `self` to allow chaining with other functions.
* Can be used with functions, to copy class methods, e.g.
*
* @param {Object} self An object to be extended
* @param {Object} obj An object which properties will be copied to self
* @param {Boolean} onlyEnumerable Optional flag to prevent copying non-enumerable properties, `false` by default
* @return {Object}
*/
{{## def.getDescriptor:_obj:
var desc = Object.getOwnPropertyDescriptor(_obj, key);
if (desc) descriptors[key] = desc;
#}}
function extend({{# def.arg }} obj, onlyEnumerable) {
var descriptors = {};
{{ var params = { obj: 'obj', code: '{{# def.getDescriptor:obj }}' }; }}
{{# def.eachKey:params }}
Object.defineProperties({{# def.self }}, descriptors);
return {{# def.this }};
}
/**
* Makes a shallow clone of object `obj` creating an instance of the same class; the properties will have the same descriptors.
* To clone an array use
* ```
* var clonedArray = [].concat(arr);
* ```
* This function should not be used to clone an array, because it is inefficient.
*
* @param {Object} self An object to be cloned
* @param {Boolean} onlyEnumerable Optional flag to prevent copying non-enumerable properties, `false` by default
* @return {Object}
*/
{{## def.clone:
var descriptors = {};
{{ var params = { obj: 'self', code: '{{# def.getDescriptor:self }}' }; }}
{{# def.eachKey:params }}
clonedObject = Object.create(self.constructor.prototype, descriptors);
#}}
function clone({{# def.arg }} onlyEnumerable) {
{{# def.varSelf }}
var clonedObject;
if (Array.isArray(self)) clonedObject = self.slice();
else if (self instanceof Date) clonedObject = new Date(self);
else if (self instanceof RegExp) clonedObject = new RegExp(self);
if (!clonedObject) { {{# def.clone }} }
{{# def.return:clonedObject }}
}
{{## def.findCode:
var item = self[key];
if (callback.call(thisArg, item, key, self)) {
result = {{= params.result }};
break;
}
#}}
{{## def.findInObj:params:
{{# def.varSelf }}
var result = {{= params.notFound }};
{{ var iterParams = { obj: 'self', code: '{{# def.findCode }}' }; }}
{{# def.eachKey:iterParams }}
{{# def.return:result }}
#}}
/**
* Analogue of ES6 [Array __find__ method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
* Returns the value of object property that passes callback test.
*
* @param {Object} self object to search in
* @param {Function} callback should return `true` for item to pass the test, passed `value`, `key` and `self` as parameters
* @param {Object} thisArg optional context (`this`) of callback call
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Any}
*/
function findValue({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{ var params = { result: 'item', notFound: 'undefined' }; }}
{{# def.findInObj:params }}
}
/**
* Analogue of ES6 [Array __findIndex__ method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex).
* Returns the key of object property that passes callback test. Returns `undefined` if not found (unlike `findIndex`, that returns -1 in this case).
*
* @param {Object} self object to search in
* @param {Function} callback should return `true` for item to pass the test, passed `value`, `key` and `self` as parameters
* @param {Object} thisArg optional context (`this`) of callback call
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Integer}
*/
function findKey({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{ var params = { result: 'key', notFound: 'undefined' }; }}
{{# def.findInObj:params }}
}
/**
* Syntax sugar to shorten usage of `Object.defineProperty`.
* The simplest usage (to add non-enumerable, non-configurable, non-writable property):
* ```
* _.defineProperty(obj, 'key', value);
* ```
*
* To define some other properties use sum of the flags `_.ENUMERABLE` (or `_.ENUM`), `_.CONFIGURABLE` (or `_.CONF`) and `_.WRITABLE` (or `_.WRIT`):
* ```
* _.defineProperty(obj, 'key', value, _.ENUM + _.WRIT);
* ```
* Returns `self`.
*
* @param {Object} self An object to add a property to
* @param {String} propertyName the name of the property that will be added
* @param {Any} value the value of added property
* @param {Integer} decriptorFlags bit mask of property descriptor properties composed from `_.ENUMERABLE` (or `_.ENUM`), `_.CONFIGURABLE` (or `_.CONF`) and `_.WRITABLE` (or `_.WRIT`)
* @return {Object}
*/
{{## def.createDescriptor:
var descriptor = { value: value };
if (decriptorFlags) {
descriptor.enumerable = !!(decriptorFlags & constants.ENUMERABLE);
descriptor.configurable = !! (decriptorFlags & constants.CONFIGURABLE);
descriptor.writable = !! (decriptorFlags & constants.WRITABLE);
}
#}}
function defineProperty({{# def.arg }} propertyName, value, decriptorFlags) {
{{# def.createDescriptor }}
Object.defineProperty({{# def.self }}, propertyName, descriptor);
return {{# def.this }};
}
/**
* Syntax sugar to shorten usage of `Object.defineProperties`.
* The simplest usage (to add non-enumerable, non-configurable, non-writable properties):
* ```
* _.defineProperties(obj, {
* key1: value1,
* key2: value2
* });
* ```
* To define some other properties use sum of the flags `_.ENUMERABLE` (or `_.ENUM`), `_.CONFIGURABLE` (or `_.CONF`) and `_.WRITABLE` (or `_.WRIT`):
* ```
* _.defineProperties(obj, {
* key1: value1,
* key2: value2
* }, _.ENUM + _.WRIT);
* ```
* Returns `self`.
*
* @param {Object} self An object to add a property to
* @param {Object} propertyValues A map of keys and values of properties thatwill be added. The descriptors of properties will be defined by the following parameters.
* @param {Integer} decriptorFlags bit mask of property descriptor properties composed from `_.ENUMERABLE` (or `_.ENUM`), `_.CONFIGURABLE` (or `_.CONF`) and `_.WRITABLE` (or `_.WRIT`)
* @return {Object}
*/
{{## def.defPropsCode:
var value = propertyValues[key];
{{# def.createDescriptor }}
descriptors[key] = descriptor;
#}}
function defineProperties({{# def.arg }} propertyValues, decriptorFlags) {
{{# def.varSelf }}
var descriptors = {};
{{ var params = { obj: 'propertyValues', code: '{{# def.defPropsCode }}' }; }}
{{# def.eachKeyAll:params }}
Object.defineProperties(self, descriptors);
{{# def.return:self }}
}
/**
* Extends object `self` with properties of `obj` to any depth, without overwrtiting existing object properties of `self` with object properties of `obj`.
* Scalar properties of `obj` will overwrite properties of `self`. Scalar porperties of `self` will also be overwritten.
* Correctly works with recursive objects.
* Usage:
* ```
* var obj = {
* inner: {
* a: 1
* }
* };
*
* _.deepExtend(obj, {
* inner: {
* b: 2
* }
* });
*
* assert.deepEqual(obj, {
* inner: {
* a: 1,
* b: 2
* }
* }); // assert passes
* ```
* Returns `self`.
*
* @param {Object} self An object to be extended
* @param {Object} obj An object with properties to copy to
* @param {Boolean} onlyEnumerable Optional `true` to use only enumerable properties
* @param {Boolean} preserveStructure if true will throw at the attempt to overwrite object with scalar value (including Date and Regex) and vice versa
* @return {Object}
*/
function deepExtend({{# def.arg }} obj, onlyEnumerable, preserveStructure) {
var result = _extendTree({{# def.self }}, obj, onlyEnumerable, preserveStructure, []);
{{# def.return:result }}
}
{{## def.isNormalObject:_value:
typeof _value == "object"
&& _value != null
&& !(_value instanceof RegExp) && !(_value instanceof Date)
#}}
{{## def.deepExtendCode:
var value = objNode[key];
var hasProp = selfNode.hasOwnProperty(key);
var selfValue = selfNode[key];
var isSelfObj = {{# def.isNormalObject:selfValue }};
var isValueObj = {{# def.isNormalObject:value }};
if (preserveStructure && hasProp && isSelfObj != isValueObj)
throw new Error("deepExtend");
if (isValueObj) {
if (!hasProp || !isSelfObj)
selfNode[key] = (Array.isArray(value)) ? [] : {};
_extendTree(selfNode[key], value, onlyEnumerable, preserveStructure, objTraversed);
} else {
var descriptor = Object.getOwnPropertyDescriptor(objNode, key);
if (descriptor) Object.defineProperty(selfNode, key, descriptor);
}
#}}
function _extendTree(selfNode, objNode, onlyEnumerable, preserveStructure, objTraversed) {
if (objTraversed.indexOf(objNode) >= 0) return selfNode; // node already traversed, obj has recursion
// store node to recognise recursion
objTraversed.push(objNode);
if (Array.isArray(objNode)) {
for (var key=0; key<objNode.length; key++) {
{{# def.deepExtendCode }}
}
} else {
{{ var params = { obj: 'objNode', code: '{{# def.deepExtendCode }}' }; }}
{{# def.eachKey:params }}
}
objTraversed.pop();
return selfNode;
}
/**
* Clones all object tree. Class of original object is not preserved. Returns `self`
*
* @param {Object} self An object to be extended
* @param {Boolean} onlyEnumerable Optional `true` to use only enumerable properties
* @return {Object}
*/
function deepClone({{# def.arg }} onlyEnumerable) {
{{# def.varSelf }}
var clonedObject;
if (self instanceof Date) clonedObject = new Date(self);
else if (self instanceof RegExp) clonedObject = new RegExp(self);
else {
clonedObject = Array.isArray(self) ? [] : {};
_extendTree(clonedObject, self, onlyEnumerable, false, []);
}
{{# def.return:clonedObject }}
}
/**
* Returns array of enumerable properties of the object
*
* @param {Object} self object to return keys of
* @return {Array}
*/
function keys({{# def.oneArg }}) {
var keys = Object.keys({{# def.self }});
{{# def.return:keys }}
}
/**
* Returns array of all property names of an object `self` (including non-enumerbale).
* To get only enumerable properties, use `Object.keys()`.
*
* @param {Object} self An object to get all properties of.
* @return {Array}
*/
function allKeys({{# def.oneArg }}) {
var keys = Object.getOwnPropertyNames({{# def.self }});
{{# def.return:keys }}
}
/**
* Returns array of values of the object's keys
*
* @param {Object} self object to return values from
* @return {Array}
*/
{{## def.valuesCode:
arr[arr.length] = self[key];
#}}
function values({{# def.arg }} onlyEnumerable) {
var arr = [];
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.valuesCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:arr }}
}
/**
* An analogue of `indexOf` method of Array prototype.
* Returns the `key` of `searchElement` in the object `self`.
* As object keys are unsorted, if there are several keys that hold `searchElement` any of them can be returned. Use `allKeysOf` to return all keys.
* All own properties are searched (not those inherited via prototype chain), including non-enumerable properties (unless `onlyEnumerable` is truthy).
*
* @param {Object} self An object to search a value in
* @param {Any} searchElement An element that will be searched. An exact equality is tested, so `0` is not the same as `'0'`.
* @param {Boolean} onlyEnumerable An optional true to search among enumerable properties only.
* @return {String}
*/
{{## def.keyOfCode:
if (searchElement === self[key]) {
foundKey = key;
break;
}
#}}
function keyOf({{# def.arg }} searchElement, onlyEnumerable) {
var foundKey;
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.keyOfCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:foundKey }}
}
/**
* Works similarly to the previous function, but returns the array of keys holding `searchElement` as their value.
*
* @param {Object} self An object to search a value in
* @param {Any} searchElement An element that will be searched. An exact equality is tested, so `0` is not the same as `'0'`.
* @param {Boolean} onlyEnumerable An optional true to search among enumerable properties only.
* @return {Array<String>}
*/
{{## def.allKeysOfCode:
if (searchElement === self[key]) {
foundKeys[foundKeys.length] = key;
}
#}}
function allKeysOf({{# def.arg }} searchElement, onlyEnumerable) {
var foundKeys = [];
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.allKeysOfCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:foundKeys }}
}
/**
* An analogue of [forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) method of Array prototype.
* Iterates all own properties of `self` (or only enumerable own properties if `onlyEnumerable` is truthy) calling callback for each key.
* This method should not be used with arrays, it will include `length` property in iteration.
* To iterate array-like objects (e.g., `arguments` pseudo-array) use:
* ```
* _.forEach(arguments, callback, thisArg);
* ```
* Function returns `self` to allow [chaining](proto.js.html)
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `value`, `key` and `self`, its return value is not used.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
*/
{{## def.eachKeyCode:
callback.call(thisArg, self[key], key, self);
#}}
function eachKey({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.eachKeyCode }}' }; }}
{{# def.eachKey:params }}
return {{# def.this }};
}
/**
* An analogue of [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) method of Array prototype.
* Returns the object that is the result of the application of callback to values in all own properties of `self` (or only enumerable own properties if `onlyEnumerable` is truthy).
* The returned object will be the instance of the same class as `self`.
* Property descriptors of the returned object will have the same `enumerable`, `configurable` and `writable` settings as the properties of `self`.
* This method should not be used with arrays, it will include `length` property in iteration.
* To map array-like objects use:
* ```
* var result = _.map(arguments, callback, thisArg);
* ```
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `value`, `key` and `self` and should return value that will be included in the map.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Object}
*/
{{## def.mapCode:
descriptors[key] = Object.getOwnPropertyDescriptor(self, key);
descriptors[key].value = callback.call(thisArg, self[key], key, self);
#}}
function mapKeys({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{# def.varSelf }}
var descriptors = {};
{{ var params = { obj: 'self', code: '{{# def.mapCode}}' }; }}
{{# def.eachKey:params }}
var obj = Object.create(self.constructor.prototype, descriptors);
{{# def.return:obj }}
}
/**
* An analogue of [reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method of Array prototype.
* This method reduces the object to a single value. Iteration order is impossible to control with object.
* This method should not be used with arrays, it will include `length` property in iteration.
* To reduce array-like objects use:
* ```
* var result = _.reduce(arguments, callback, initialValue, thisArg);
* ```
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `previousValue`, `value`, `key` and `self` and should return value that will be used as the `previousValue` for the next `callback` call.
* @param {Any} initialValue The initial value passed to callback as the first parameter on the first call.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Any}
*/
{{## def.reduceKeysCode:
memo = callback.call(thisArg, memo, self[key], key, self);
#}}
function reduceKeys({{# def.arg }} callback, initialValue, thisArg, onlyEnumerable) {
var memo = initialValue;
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.reduceKeysCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:memo }}
}
/**
* An analogue of [filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) method of Array prototype.
* Returns the new object with keys for which callback returns true.
* Property descriptors of the returned object will have the same `enumerable`, `configurable` and `writable` settings as the properties of `self`.
* To filter array-like objects use:
* ```
* var result = _.filter(arguments, callback, thisArg);
* ```
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `value`, `key` and `self`. If it returns truthy value, the key/value will be included in the resulting object.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Object}
*/
{{## def.filterKeysCode:
if (callback.call(thisArg, self[key], key, self))
descriptors[key] = Object.getOwnPropertyDescriptor(self, key);
#}}
function filterKeys({{# def.arg }} callback, thisArg, onlyEnumerable) {
var descriptors = {};
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.filterKeysCode }}' }; }}
{{# def.eachKey:params }}
var obj = Object.create(self.constructor.prototype, descriptors);
{{# def.return:obj }}
}
var _passed = {}
, _didNotPass = {};
/**
* An analogue of [some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) method of Array prototype.
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `value`, `key` and `self`. If it returns truthy value, the function immeaditely returns `true`.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Boolean}
*/
{{## def.someKeyCode:
if (callback.call(thisArg, self[key], key, self))
return true;
#}}
function someKey({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.someKeyCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:false }}
}
/**
* An analogue of [every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) method of Array prototype.
*
* @param {Object} self An object which properties will be iterated
* @param {Function} callback Callback is passed `value`, `key` and `self`. If it returns falsy value, the function immeaditely returns `false`.
* @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.
* @param {Boolean} onlyEnumerable An optional `true` to iterate enumerable properties only.
* @return {Boolean}
*/
{{## def.everyKeyCode:
if (!callback.call(thisArg, self[key], key, self))
return false;
#}}
function everyKey({{# def.arg }} callback, thisArg, onlyEnumerable) {
{{# def.varSelf }}
{{ var params = { obj: 'self', code: '{{# def.everyKeyCode }}' }; }}
{{# def.eachKey:params }}
{{# def.return:true }}
}
/**
* Returns object of the same class with only specified keys, that are passed as string parameters or array(s) of keys.
*
* @param {Object} self an object to pick keys from
* @param {List<String|Array>} arguments list of keys (or array(s) of keys)
* @return {Object}
*/
{{## def.start: {{= it.mode == 'functions' ? '1' : '0' }} #}}
{{## def.argKeys: var keys = concat.apply(Array.prototype, arguments); #}}
function pickKeys({{# def.oneArg }}) { // , ... keys
{{# def.varSelf }}
{{# def.argKeys }}
var obj = Object.create(self.constructor.prototype);
for (var i={{#def.start}}; i<keys.length; i++) {
var key = keys[i];
if (self.hasOwnProperty(key)) obj[key] = self[key];
}
{{# def.return:obj }};
}
/**
* Returns object of the same class without specified keys, that are passed as string parameters or array(s) of keys.
*
* @param {Object} self an object to omit keys in
* @param {List<String|Array>} arguments list of keys (or array of keys)
* @return {Object}
*/
function omitKeys({{# def.oneArg}}) { // , ... keys
{{# def.varSelf }}
var clonedObject, onlyEnumerable;
{{# def.clone }}
{{# def.argKeys }}
for (var i={{#def.start}}; i<keys.length; i++) {
delete clonedObject[keys[i]];
}
{{# def.return:clonedObject }};
}
/**
* Performs deep equality test of the object. Does not work with recursive objects
* @param {Any} self object to compare
* @param {Any} obj object to compare
* @return {Boolean}
*/
function isEqual({{# def.arg }} obj) {
{{# def.varSelf }}
var result;
if (self === obj) {
result = self !== 0 || 1/self == 1/obj; // 0 and -0 are considered not equal, although 0 === -0 is true
{{# def.return:result }}
}
if (self == null || obj == null) {
{{# def.return:false }}
}
var className = self.constructor.name;
if (className != obj.constructor.name) {
{{# def.return:false }}
}
switch (className) {
case 'String':
result = self == String(obj);
break;
case 'Number':
result = self != +self ? obj != +obj : (self == 0 ? 1/self == 1/obj : self == +obj);
break;
case 'Date':
case 'Boolean':
result = +self == +obj;
break;
case 'RegExp':
result = self.source == obj.source
&& self.global == obj.global
&& self.multiline == obj.multiline
&& self.ignoreCase == obj.ignoreCase;
break;
default:
if (typeof self != 'object' || typeof obj != 'object') {
{{# def.return:false }}
}
if (Array.isArray(self)) {
if (self.length != obj.length) {
{{# def.return:false }}
}
{{# def.iter:self }} {
result = {{? it.mode == 'functions' }}
isEqual(self[i], obj[i]);
{{??}}
isEqual.call({self: self[i]}, obj[i]).self;
{{?}}
if (!result) {
{{# def.return:false }}
}
}
{{# def.return:true }}
} else {
if ({{#def.allKeys:'self'}}.length != {{#def.allKeys:'obj'}}.length) {
{{# def.return:false }}
}
{{
var isEqualCode = 'result = '
+ (it.mode == 'functions'
? 'isEqual(self[key], obj[key]);'
: 'isEqual.call({self: self[key]}, obj[key]).self;' )
+ 'if (!result) break;';
}}
result = true;
{{ var params = { obj: 'self', code: isEqualCode }; }}
{{# def.eachKeyAll:params }}
{{# def.return:result }}
}
}
{{# def.return:result }}
}
/**
* The opposite of isEqual
* @param {Any} self object to compare
* @param {Any} obj object to compare
* @return {Boolean}
*/
function isNot({{# def.arg }} obj) {
var equal = {{? it.mode == 'functions' }}
!isEqual(self, obj);
{{??}}
!isEqual.call({self: this.self}, obj).self;
{{?}}
{{# def.return:equal }}
}