BonsaiDen / JavaScript-Garden

A collection of documentation about the most quirky parts of the JavaScript language.
http://bonsaiden.github.com/JavaScript-Garden
MIT License
3.45k stars 557 forks source link

safer call to hasOwnProperty #4

Closed kosta closed 13 years ago

kosta commented 13 years ago

Hello!

Wouldn't it be safer to use

({}).hasOwnProperty.call(o, ['foo'])

instead of

o.hasOwnProperty('foo')

?

Consider this:

var o = {foo: 5, hasOwnProperty: function() { return false; } };

This might especially be important if you're allowing the user to just store about anything in an object. Or are there any keys that definitely "break" a JavaScript object, even if using tricks like the one above?

Raynos commented 13 years ago

This is only valid if your writing a library or a framework for external use. In which case you would have a line at the top of your (thousands) of lines of code like

var hasOwnProperty = Object.prototype.hasOwnProperty

For almost all normal use it's safe to assume someone isn't a complete idiot and overwrites methods defined on Object.prototype. Only in cases where your dealing with completely untrusted 3rd party code would you need this.

Like for example libraries like underscore.js and jquery.js need to be this idiot proof.

ghost commented 13 years ago

Raynos: yeah, agreed.

BonsaiDen commented 13 years ago

As Raynos already said, this mainly benefits fool-proof libraries. I may add a note though, for those out there who might think that hasOwnProperty cannot be overwritten. But in the end, there will always be a way in which you can break things in JS.

kosta commented 13 years ago

Hi!

The idea wasn't that much on making a library in the face of a developer who does extremely foolish thing. I was more thinking about what to consider when using a JavaScript object as the equivalent of C++ std::map<string, Object>, Python's dict or Rubys Hash.

Consider we want to have a object to store all our friends by value. They might be called "Ryan", "Brendan", "Douglas" and "hasOwnProperty". In none of the languages quoted above, our friend with the weird name would break anything. In JS, one option is to add a prefix to all names (e.g. "mapped_" or whatever). Another option is to just accept all keys are they are and use the trick in original issue to work it out.

I'm not a JS expert so I don't know if that's even possible, considering other friends might be called "prototype", "proto", "constructor" or "defineGetter". But if that's a viable path, one might want to mention the trick above.

Of course, that might be a whole chapter in a whole different book, when I think about it... :)

Cheers, Kosta

Edit: escaped markdown for foo

BonsaiDen commented 13 years ago

And now you have two friends with the same name... ;)

In the end, you use an array or an object with IDs as keys :P

Raynos commented 13 years ago

If you want to garantuee that using keys doesn't break anything you'll need a wrapper for the native object type. The thing is, javascript is dynamic, these things can't be avoided without losing your runtime dynamic nature of the language. In the languages you quoted you actaully just pass a key, value pair in which is stored internally.

kosta commented 13 years ago

I found a better example. Lets say you want to count the words in a text. Here's the naive approach:

function count(text) {
    var words = text.match(/[\w+']/g),
        counts = {}, 
        i, n = words.length;
    for(i = 0; i < n; ++i) {
        if (counts.hasOwnProperty(words[i])) {
            counts[i]++;
        } else {
            counts[i] = 1;
        }
    }
    return counts;
}

Now, if "hasOwnProperty" appears in the text, we're screwed. Are there other words that also screw us? Is there another way to fix this except

var prefix = 'word_';
...
counts[prefix+i] = ...
BonsaiDen commented 13 years ago

Well in this case {},hasOwnProperty() would indeed be a good solution. I'll add a note about the possibility of hasOwnProperty being set and the solution.

@Raynos Just a note on the "idiot" proof thing, jQuery dropped the use of hasOwnProperty they just don't care anymore.

BonsaiDen commented 13 years ago

Pushed: https://github.com/BonsaiDen/JavaScript-Garden/commit/558d91af21ad3c9f02890b84d5b73f50d92acc33

Closing now.