Skip to content

Commit

Permalink
#14 add safer version of hasOwnProperty()
Browse files Browse the repository at this point in the history
#15 forEachKey() should ignore inherited properties
Reviewed by: Joshua M. Clulow <[email protected]>
Reviewed by: Alex Wilson <[email protected]>
  • Loading branch information
Dave Pacheco committed Jun 23, 2016
1 parent 0e70987 commit b5acfc2
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@ Returns whether two objects are equal.
Returns true if the given object has no properties and false otherwise. This
is O(1) (unlike `Object.keys(obj).length === 0`, which is O(N)).

### hasKey(obj, key)

Returns true if the given object has an enumerable, non-inherited property
called `key`. [For information on enumerability and ownership of properties, see
the MDN
documentation.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)

### forEachKey(obj, callback)

Like Array.forEach, but iterates properties of an object rather than elements
of an array. Equivalent to:
Like Array.forEach, but iterates enumerable, owned properties of an object
rather than elements of an array. Equivalent to:

for (var key in obj)
callback(key, obj[key]);
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
callback(key, obj[key]);
}
}


### flattenObject(obj, depth)
Expand Down
14 changes: 12 additions & 2 deletions lib/jsprim.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var mod_jsonschema = require('json-schema');
exports.deepCopy = deepCopy;
exports.deepEqual = deepEqual;
exports.isEmpty = isEmpty;
exports.hasKey = hasKey;
exports.forEachKey = forEachKey;
exports.pluck = pluck;
exports.flattenObject = flattenObject;
Expand Down Expand Up @@ -122,10 +123,19 @@ function isEmpty(obj)
return (true);
}

function hasKey(obj, key)
{
mod_assert.equal(typeof (key), 'string');
return (Object.prototype.hasOwnProperty.call(obj, key));
}

function forEachKey(obj, callback)
{
for (var key in obj)
callback(key, obj[key]);
for (var key in obj) {
if (hasKey(obj, key)) {
callback(key, obj[key]);
}
}
}

function pluck(obj, key)
Expand Down
37 changes: 37 additions & 0 deletions test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ mod_assert.ok(!jsprim.deepEqual(NaN, NaN));
mod_assert.ok(jsprim.isEmpty({}));
mod_assert.ok(!jsprim.isEmpty({ 'foo': 'bar' }));

/* hasKey */
mod_assert.ok(jsprim.hasKey(obj, 'family'));
mod_assert.ok(jsprim.hasKey(obj, 'children'));
mod_assert.ok(jsprim.hasKey(obj, 'home'));
mod_assert.ok(jsprim.hasKey(obj, 'income'));
mod_assert.ok(jsprim.hasKey(obj, 'dignity'));
mod_assert.ok(jsprim.hasKey(obj, 'nhomes'));
mod_assert.ok(obj.hasOwnProperty);
mod_assert.ok(!jsprim.hasKey(obj, 'hasOwnProperty'));
copy = Object.create(obj);
copy.aprop = 'avalue';
mod_assert.ok(jsprim.hasKey(copy, 'aprop'));
mod_assert.equal(copy.nhomes, 1);
mod_assert.ok(!jsprim.hasKey(copy, 'nhomes'));
copy.hasOwnProperty = null;
mod_assert.ok(jsprim.hasKey(copy, 'aprop'));
mod_assert.ok(!jsprim.hasKey(copy, 'nhomes'));

/* forEachKey */
var keys = [];
jsprim.forEachKey(obj, function (key, val) {
Expand All @@ -70,6 +88,25 @@ keys.sort();
mod_assert.deepEqual(keys,
[ 'children', 'dignity', 'family', 'home', 'income', 'nhomes' ]);

/*
* forEachKey skips non-own properties and works even on objects with a
* hasOwnProperty key overridden.
*/
copy = jsprim.deepCopy(obj);
Object.prototype.aprop = 'avalue';
mod_assert.equal(copy.aprop, 'avalue');
copy.hasOwnProperty = null;
keys = [];
jsprim.forEachKey(copy, function (key, val) {
mod_assert.deepEqual(copy[key], val);
keys.push(key);
});
keys.sort();
mod_assert.deepEqual(keys, [ 'children', 'dignity', 'family',
'hasOwnProperty', 'home', 'income', 'nhomes' ]);
delete (Object.prototype.aprop);


/* startsWith */
mod_assert.ok(jsprim.startsWith('foobar', 'f'));
mod_assert.ok(jsprim.startsWith('foobar', 'foo'));
Expand Down

0 comments on commit b5acfc2

Please sign in to comment.