Мой дядя самых честных правил программ исходники за так ...

7 мар. 2009 г.

JavaScript: Никогда не переопределяйте Object.prototype!!

Вот уже в который раз наблюдаю использование в коде сторонней библиотеки попытки сделать всё красиво за счёт добавления функций в Object.prototype.

    Object.prototype.Foo = function()

    {

        // Что-то делаем здесь.

    }

На первый взгляд может показаться, что нет ничего страшного в таком коде. Но, стоит только вспомнить один из самых распространённых вариантов использования объектов в JavaScript: “Object as hash-tables” и:

    var myHashTable = { "key1" : "value1", "key2" : "value2" };

 

    for (var key in myHashTable)

    {

        // используется функция логирования от расширения Firebug (http://getfirebug.org/).

        console.log("key = '" + key + "', value = '" + myHashTable[key] + "';");

    }

 

    // Вывод:

    // key = 'key1', value = 'value1';

    // key = 'key2', value = 'value2';

    // key = 'Foo', value = 'function () { }'; // WTF???

Упс. В импровизированной хэш-табличке, внезапно, появился новый забавный элемент.

Неприятно обнаруживать, что ошибки в твоём коде обусловлены использованием чужой библиотекой. Да и избавиться от такого бага довольно непросто: он заставляет либо отказаться от использования “Объект как хэш-таблица” (подменив на свою реализацию), либо от использования сторонней библиотеки (в некоторых случаях гораздо проще).

Чтобы обнаружить этот баг на ранней стадии, имеет смысл добавить в свои unit-тесты следующий тест:

    testObjectAsHashTableAreEmptyByDefault = function()

    {

        var obj = {};

 

        var keysCount = 0;

        for (var key in obj) { keysCount++; }

 

        assertEquals(keysCount, 0);

    }

Разработчикам же, библиотек для JavaScript нелишне будет запомнить, что Object.prototype – это тайна за семью печатями (sealed).

4 комментария:

  1. Добрый вечер.
    Простите за глупый вопрос, но Object.prototype подразумевается любой объект, правильно?

    И тогда вопрос отсюда вытекающий - как тогда правильно расширить свойства объекта?

    ОтветитьУдалить
  2. Ваши бы слова да разработчикам в уши. Вот приходит ко мне пользователь моей библиотеки и просит сделать обход свойств объекта у меня, чтобы я не натыкался на его прототипированную функцию - вот где веселье.

    ОтветитьУдалить
  3. А вы пользователю скажите, чтобы он, влезая в прототип использовал
    Object.defineProperty(Array.prototype, "имя_свойства", {enumerable: false})
    Или сами у себя проверяйте hasOwnProperty

    ОтветитьУдалить

Публикуются только комментарии, которые показались автору блога заслуживающими внимания.