Расширение объекта в Javascript - PullRequest
4 голосов
/ 26 мая 2010

Я пытаюсь расширить функциональность объекта следующим образом:

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

Это здорово, но есть проблема:

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

Там будет 3 прохода цикла. Есть ли способ избежать этого?

Ответы [ 6 ]

4 голосов
/ 27 мая 2010

Я, например, не полностью против расширения нативных типов и ECMA-262 5-е издание . хорошо решает проблемы, упомянутые в других ответах и ​​связанных статьях для нас. Посмотрите эти слайды для хорошего обзора.

Вы можете расширить любой объект и определить дескрипторы свойств, которые управляют поведением этих свойств. Свойство может быть сделано не перечисляемым, что означает, что при доступе к свойствам объектов в цикле for..in это свойство не будет включено.

Вот как вы можете определить метод getType для самого Object.prototype и сделать его не перечисляемым:

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

Функция getType, приведенная выше, в основном бесполезна, поскольку она просто возвращает typeof object, который в большинстве случаев будет просто объектом, но он только для демонстрации.

[].getType();
{}.getType();
(6).getType();
true.getType();
3 голосов
/ 26 мая 2010

Вы можете использовать метод hasOwnProperty(), чтобы проверить, принадлежит ли свойство объекту foo:

var foo = { 'bar' : 'eggs' };
for (var key in foo) {
   if (foo.hasOwnProperty(key)) {
      alert(key);
   }
}
3 голосов
/ 26 мая 2010

Вы не должны расширять прототип объекта по той же причине:

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

Вместо этого используйте статический метод.

Если у вас есть выбор нет , вы можете использовать метод hasOwnProperty:

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

for(var prop in x){
  if(x.hasOwnProperty(prop)){
    console.log(prop);
  }
}
2 голосов
/ 26 мая 2010

Есть ли способ избежать этого?

Да, не расширять нативные типы.

Вместо этого используйте обертку:

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

Использование:

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

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

for(var i in obj) { ... works properly }
1 голос
/ 26 мая 2010

Когда вы перебираете перечисляемые свойства объекта, вы можете определить, было ли текущее свойство «унаследовано» или нет с помощью Object.hasOwnProperty ()

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

Но позвольте вам знать об опасностях исправления обезьян , особенно на Object, как другие писали о

1 голос
/ 26 мая 2010

Создайте свой собственный объект вместо расширения объекта по умолчанию.

Также см .:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...