__proto__, когда он исчезнет? Альтернативы?

Mozilla заявила, что удалит __proto__ некоторое время назад (~ 2008), и она все еще находится в браузере. Неужели это будет устаревшим? Он работает в Opera, (думаю, Safari) и Chrome. Мне не нужно беспокоиться об IE, поэтому я хотел бы продолжать использовать его.

Однако я не хочу, чтобы мой код переставал работать в один прекрасный день, поэтому на мой вопрос:

__ proto__ допускает мертвое простое наследование:

a.__proto__ = {'a':'test'}

В любом случае, я могу воспроизвести это стандартным образом? Я знаю, что есть функциональное наследование, это уродливое, и это слишком усложняет тот факт, что я просто хочу создать цепочку прототипов. Просто интересно, решили ли какие-либо мастера.

Спасибо

Ответы

Ответ 1

Примечание.. По мнению плохой практики, изменить значение __proto__. Этому сильно препятствует Брендан Эйх, создатель JavaScript, среди прочих. Фактически свойство __proto__ полностью удалено из нескольких движков JavaScript, таких как Rhino. Если вы хотите знать, почему тогда читайте после комментария от Brendan Eich.

Обновление: Браузеры не собираются удалить свойство __proto__. Фактически, ECMAScript Harmony теперь стандартизовал как __proto__ и setPrototypeOf. Свойство __proto__ поддерживается только по устаревшим причинам. Вам настоятельно рекомендуется использовать setPrototypeOf и getPrototypeOf вместо __proto__.

Предупреждение: Хотя setPrototypeOf теперь является стандартом, вам все еще не рекомендуется использовать его, поскольку мутация прототип объекта неизменно убивает оптимизацию и делает ваш код медленнее. Кроме того, использование setPrototypeOf обычно является показателем низкого качества кода.


Вам не нужно беспокоиться о том, что ваш существующий код не работает в один прекрасный день. Свойство __proto__ находится здесь.

Теперь, для вопроса. Мы хотим сделать что-то подобное этому стандартным образом:

var a = {
    b: "ok"
};

a.__proto__ = {
    a: "test"
};

alert(a.a); // alerts test
alert(a.b); // alerts ok

Очевидно, вы не можете использовать Object.create для достижения этой цели, так как мы не создаем новый объект. Мы просто пытаемся изменить внутреннее свойство [[proto]] данного объекта. Проблема заключается в том, что невозможно изменить внутреннее свойство [[proto]] объекта после его создания (за исключением использования __proto__, которое мы пытаемся избежать).

Итак, чтобы решить эту проблему, я написал простую функцию (обратите внимание, что она работает для всех объектов, кроме функций):

function setPrototypeOf(obj, proto) {
    var result  = Object.create(proto);
    var names   = Object.getOwnPropertyNames(obj);
    var getProp = Object.getOwnPropertyDescriptor;
    var setProp = Object.defineProperty;
    var length  = names.length;
    var index   = 0;

    while (index < length) {
        var name = names[index++];
        setProp(result, name, getProp(obj, name));
    }

    return result;
}

Итак, теперь мы можем изменить прототип любого объекта после его создания следующим образом (обратите внимание, что мы фактически не изменяем внутреннее свойство [[proto]] объекта, а вместо этого создаем новый объект с теми же свойствами, что и данный объект, и который наследуется от данного прототипа):

var a = {
    b: "ok"
};

a = setPrototypeOf(a, {
    a: "test"
});

alert(a.a); // alerts test
alert(a.b); // alerts ok
<script>
function setPrototypeOf(obj, proto) {
    var result  = Object.create(proto);
    var names   = Object.getOwnPropertyNames(obj);
    var getProp = Object.getOwnPropertyDescriptor;
    var setProp = Object.defineProperty;
    var length  = names.length;
    var index   = 0;

    while (index < length) {
        var name = names[index++];
        setProp(result, name, getProp(obj, name));
    }

    return result;
}
</script>

Ответ 2

Я думаю, что фактический момент, который хотел сделать Mozilla, заключается в том, что он нестандартен, поэтому разработчики будут полностью в пределах своих прав, удаляя его.

Более чистый способ создания прототипных цепей - Object.create. Эквивалентом вашего кода для создания объекта a с прототипом {'a': 'test'} является:

a = Object.create({'a':'test'})

Есть также прокладки, имитирующие эту функцию в браузерах, которые ее не поддерживают, если вам когда-либо понадобится работать с одним, что является еще одним преимуществом по сравнению с тем, что происходит с помощью __proto__.

Ответ 3

Я не вижу, как:

var a = {};
a.__proto__ = A; // A is object because no constructor is needed

Проще чем:

var a = new A(); // A is Constructor function

Теперь настройка A в последнем случае может быть более подробной, если вам не нужна функция конструктора, но в этом случае вы могли бы автоматизировать его так же просто:

var A = Constructor({
    method: function(){}
}); // A is function, meant to be used with new

По сравнению с:

var A = {
    method: function(){}
}; //A is object, meant to be set as __proto__

И если вам нужна логика инициализации, то, вероятно, в конечном итоге будет проще просто использовать обычный способ, в котором функция конструктора должна быть объявлена ​​в любом случае