4

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?

2
  • I highly recommend Prototypal Inheritance in JavaScript and Classical Inheritance in JavaScript if you haven't already read them. They're useful when trying to grok OOP in JavaScript. NOTE: The Prototypal post is newer than the Classical post, so I'd consider it authoritative if you spot a conflict or change in opinion. Commented May 26, 2010 at 14:16
  • Don't! Just... don't! Every time you add something to a function's prototype's that you don't own, a person dies, just like that!!! Commented May 26, 2010 at 14:28

6 Answers 6

4

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();
Sign up to request clarification or add additional context in comments.

2 Comments

is this only as of ECMA-262 5th edition? in other words, in terms of browsers, how widely supported is this? thanks!
Yes, it was implemented in ES5. You can see an up-to-date implementation status for different browsers here.
3

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

2 Comments

aw you were just a few seconds faster with posting it haha
The article that you link to argues that extending the Object Prototype is bad because the properties you added will be enumerable and show up when using the in operator. However, with Object.defineProperty you can set those properties so that they are not enumerable. This seems to fix that issue, though there is no assurance of others issues created by extending the object prototype.
3

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

1 Comment

And if i write some kind of framework? It'll be non-simple to use.
2

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 }

Comments

1

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

Comments

1

Create your own object instead of extending the default Object.

Also see:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.