tags:

views:

106

answers:

6

I'm trying to extend Object functionality this way:

Object.prototype.get_type = function() {
    if(this.constructor) {
        var r = /\W*function\s+([\w\$]+)\(/;
        var match = r.exec(this.constructor.toString());
        return match ? match[1].toLowerCase() : undefined;
    }
    else {
        return typeof this;
    }
}

It's great, but there is a problem:

var foo = { 'bar' : 'eggs' };
for(var key in foo) {
    alert(key);
}

There'll be 3 passages of cycle. Is there any way to avoid this?

+3  A: 

You shouldn't extend the object prototype, for that exact reason:

http://erik.eae.net/archives/2005/06/06/22.13.54/

Use a static method instead.

If you have no choice, you can use the "hasOwnProperty" method:

Object.prototype.foo = function(){ alert('x'); }
var x = { y: 'bar' };

for(var prop in x){
  if(x.hasOwnProperty(prop)){
    console.log(prop);
  }
}
jvenema
Thx, cap. I wrote why it's not working.
smsteel
aw you were just a few seconds faster with posting it haha
CharlesLeaf
+3  A: 

You can use the hasOwnProperty() method to check if the property belongs to the foo object:

var foo = { 'bar' : 'eggs' };
for (var key in foo) {
   if (foo.hasOwnProperty(key)) {
      alert(key);
   }
}
Daniel Vassallo
And if i write some kind of framework? It'll be non-simple to use.
smsteel
+1  A: 

Create your own object instead of extending the default Object.

Also see:

CharlesLeaf
+1  A: 

When you loop over enumerable properties of an object, you can can determin if the current property was "inherited" or not with Object.hasOwnProperty()

for ( var key in foo )
{
  if ( foo.hasOwnProperty( key ) )
  {
    alert(key);
  }
}

But let the dangers of monkey patching be known to ye, especially on Object, as others have posted about

Peter Bailey
+1  A: 

Is there any way to avoid this?

Yes, don't extend native types.

Use a wrapper instead:

var wrapper = (function(){

    var wrapper = function(obj) {
        return new Wrapper(obj);
    };

    function Wrapper(o) {
        this.obj = obj;
    }

    Wrapper.prototype = wrapper.prototype;

    return wrapper;

}());

// Define your get_type method:
wrapper.prototype.get_type = function(){
    if(this.obj.constructor) {
        var r = /\W*function\s+([\w\$]+)\(/;
        var match = r.exec(this.obj.constructor.toString());
        return match ? match[1].toLowerCase() : undefined;
    }
    else {
        return typeof this.obj;
    }
};

Usage:

var obj = { 'bar' : 'eggs' };

alert(wrapper(obj).get_type());

for(var i in obj) { ... works properly }
J-P
+1  A: 

I, for one, am not completely against extending native types and ECMA-262 5th ed. solves the problems mentioned in other answers and linked articles for us in a nice manner. See these slides for a good overview.

You can extend any object and define property descriptors that control the behavior of those properties. The property can be made non enumerable meaning when you access the objects properties in a for..in loop, that property will not be included.

Here's how you can define a getType method on Object.prototype itself, and make it non enumerable:

Object.defineProperty(Object.prototype, "getType", {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function() {
        return typeof this;
    }
});

// only logs "foo"
for(var name in { "foo": "bar" }) {
    console.log(name); 
}

The getType function above is mostly useless as it simply returns the typeof object which in most cases will simply be object, but it's only there for demonstration.

[].getType();
{}.getType();
(6).getType();
true.getType();
Anurag