UnstableFractal
UnstableFractal

Reputation: 1422

Extending Object in Javascript

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?

Upvotes: 4

Views: 389

Answers (6)

Anurag
Anurag

Reputation: 141909

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();

Upvotes: 4

CharlesLeaf
CharlesLeaf

Reputation: 3201

Create your own object instead of extending the default Object.

Also see:

Upvotes: 1

James
James

Reputation: 112000

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 }

Upvotes: 2

Peter Bailey
Peter Bailey

Reputation: 105914

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

Upvotes: 1

Daniel Vassallo
Daniel Vassallo

Reputation: 344521

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);
   }
}

Upvotes: 3

Jerod Venema
Jerod Venema

Reputation: 44652

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);
  }
}

Upvotes: 3

Related Questions