4

Provided that the object MAY contain own property called "hasOwnProperty":

> a={abc: 123};
{ abc: 123 }
> a.hasOwnProperty("abc");
true
> a['hasOwnProperty'] = 1;
1
> a.hasOwnProperty("abc");
TypeError: a.hasOwnProperty is not a function
...

This works, kinda ugly interface, if you think about Object.keys(), Object.assign() ETC.. So, is there a better way?

> Object.hasOwnProperty.call(a, "abc");
true
> Object.hasOwnProperty.call(a, "hasOwnProperty");
true

And why shouldn't the solution be the only recommended way? Using methods directly from an object seems like a recipe for a failure, especially if it is containing external data (not in one's control)

niry
  • 3,238
  • 22
  • 34
  • Might be helpful: http://stackoverflow.com/questions/12017693/why-use-object-prototype-hasownproperty-callmyobj-prop-instead-of-myobj-hasow – tymeJV Jan 12 '17 at 02:18

3 Answers3

0

The appropriate/recommended way to use hasOwnProperty is as a filter, or a means to determine whether an object... well, has that property. Just they way you are using it in your second command a.hasOwnProperty('abc').

By overwriting the Object hasOwnProperty property with a['hasOwnProperty'] = 1, while it's safe and valid, just removes the ability to use the hasOwnProperty function on that Object.

Am I missing your true question here? It seems like you already knew this from your example.

By

'using methods directly from an object seems like a recipe for a failure

are you referring to something like this:

 > dog = {speak: function() {console.log('ruff! ruff!')}};
 > dog.speak(); // ruff! ruff!

Because that is extremely useful in many ways as you can imagine.

  • I'm referring to loading data (such as tokenizing a document) into an object. The document might be about javascript and might contain the token 'hasOwnProperty'. Of course using objects with methods is powerful, but that's not my question. – niry Jan 12 '17 at 06:02
0

If you can use ECMAScript 2015 you can try Reflect.getOwnPropertyDescriptor. It returns a property descriptor of the given property if it exists on the object, undefined otherwise.

To simplify you can create this function:

var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;

var obj = new Object();
obj.prop = 'exists';

console.log('Using hasOwnProperty')
console.log('prop: ' + obj.hasOwnProperty('prop'));            
console.log('toString: ' + obj.hasOwnProperty('toString'));        
console.log('hasOwnProperty: ' + obj.hasOwnProperty('hasOwnProperty'));   

var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;

console.log('Using getOwnPropertyDescriptor')
console.log('prop: ' + hasOwnProp(obj, 'prop'));
console.log('toString: ' + hasOwnProp(obj, 'toString'));
console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));

obj['hasOwnProperty'] = 1;

console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));
Damian
  • 2,752
  • 1
  • 29
  • 28
  • Thanks for pointing out `Reflect.getOwnPropertyDescriptor()`. In what way it is better than `Object.hasOwnProperty.call(obj, prop)` ? – niry Jan 12 '17 at 06:09
0

Any built-in can be overridden in JS - it's generally considered best practice to avoid overriding any native methods where possible. If the original functionality is preserved it's OK as it will still behave as expected and even could possibly extended further if overridden correctly again.

As that's considered best practice I recommend either remapping the keys to avoid overriding them. If remapping the keys is not an option then you can maybe make it feel a little less messy by either locally referencing/wrapping Object.hasOwnProperty or Object.prototype.hasOwnProperty. In the case of hasOwnProperty you could possibly implement an iterator (as iterating over enumerable non-inherited properties is a very common use of hasOwnProperty) method to reduce the likelihood of its use. There's always still the risk of someone less familiar with your object attempting to directly iterate so I really feel that key mapping is the safer bet even if it does cause a slight difference in between server-side keys and local ones.

A key mapping could be as simple as a suffix using hasOwnProperty_data instead of hasOwnProperty this would mean objects would behave as expected and your IDE's autocomplete likely will still be close enough to know what the property represents.

A mapping function might look like the following:

function remapKeys(myObj){
    for(var key in myObj){
      if(Object.prototype.hasOwnProperty.call(myObj, key)){      
        if((key in Object) && Object[key] !== myObj[key]){ // Check key is present on Object and that it's different ie an overridden property
          myObj[key + "_data"] = myObj[key]; 
          delete myObj[key]; // Remove the key   
        } 
      }
    }
    return myObj; // Alters the object directly so no need to return but safer
}

// Test
var a = {};
a.hasOwnProperty = function(){ return 'overridden'; };
a.otherProp = 'test';
remapKeys(a);
console.log(a); // a { hasOwnProperty_data : function(){ return 'overridden';}, otherProp: 'test' } 
console.log(a.hasOwnProperty('otherProp')); // true
Brian
  • 2,822
  • 1
  • 16
  • 19
  • That seems like a lot of overhead (memory & code) for trying to avoid overwriting built in methods. I'd prefer to make sure it have no method at all with `Object.create(null)` – niry Jan 12 '17 at 06:06
  • You'd only need the first 11 lines and you'd only run it once after loading your data. Memory footprint for this would be minimal it modifies the object in place doesn't clone it etc. I think it's a small price to pay for having access to built-ins and avoiding confusion. The only considerations I think my example doesn't handle are nested objects - refactoring this to use recursion would handle those. The second being that it may be beneficial to have "custom mappings" as opposed to just appending a suffix. Creating an Object with a null prototype may be as confusing as overriding built-ins. – Brian Jan 12 '17 at 07:08