Правильная цепочка прототипов для функции - PullRequest
7 голосов
/ 20 декабря 2008

Каков правильный вывод (то есть правильный в стандарте ECMA) следующей программы?

function nl(x) { document.write(x + "<br>"); }
nl(Function.prototype);
nl(Function.prototype.prototype);
nl(Function.prototype.prototype == Object.prototype);
nl(Function.prototype.prototype.prototype);

Chrome и IE6 согласны в том, что:

function Empty() {}
null for Chrome / undefined for IE6
false

и затем сбой.

Выходы Mozilla:

function () { }
[object Object]
false
undefined

Правильно ли это? Кажется, что Mozilla лучше, но лучший результат -

function () { }
[object Object]
true
undefined

Ответы [ 4 ]

12 голосов
/ 20 декабря 2008

Function.prototype

С Язык ECMAScript Спецификация :

15.3.3.1 Function.prototype

Начальное значение Function.prototype: Функция прототипа объекта (раздел 15.3.4).

15.3.4 Свойства объекта-прототипа функции

Функция Объект-прототип сам по себе является функцией объект (его [[Class]] равен «Function») что при вызове принимает любой аргументы и возвращает неопределенные. значение внутреннего [[Prototype]] свойство функции-прототипа объект является прототипом объекта Object (раздел 15.3.2.1).

Это функция с «пустым телом»; если он вызывается, он просто возвращает не определено. Функциональный прототип объект не имеет значения собственное имущество; однако это наследует свойство valueOf от Прототип объекта Объект.

Я получаю этот вывод:

  • Опера: function () {[собственный код]}
  • Chrome: функция Пусто () {}
  • IE7: prototype () {[native code]}
  • FF3: function () {}

Chrome и IE7 назвали свои функции, Opera и IE7 сообщают вам, что не раскрывают реализацию. Все они согласны с этим:

nl(typeof Function.prototype); //function

Сравните это с:

nl(typeof Object.prototype); //object
nl(typeof Array.prototype); //object
nl(typeof String.prototype); // object

Function.prototype.prototype

Я получаю undefined от Opera и IE7, null от Chrome и [объект] от FF3. Кто прав? Поскольку «Объект-прототип Function сам по себе является объектом Function», не должно ли это быть круговой ссылкой на самого себя? Чтобы избежать круговой ссылки, они выбрали разные пути. Я не знаю, есть ли стандарт для этого или это до реализации, но я думаю, что объект является правильным. Кстати, здесь вы видите разницу между внутренним [[prototype]] и публичным прототипом в действии, как вы и задавали в предыдущем вопросе!

Function.prototype.prototype == Object.prototype

Это неверно, потому что это не тот же объект. Смотри выше.

Function.prototype.prototype.prototype

Только FF даст вам ответ, поскольку их реализация Function.prototype.prototype возвращает объект.

Я согласен, что ваш предложенный вывод выглядит более логичным.

Они согласны с этим:

nl(Object.prototype); // [object Object]
nl(Object.prototype.prototype); // undefined
9 голосов
/ 20 декабря 2008

То, что вы здесь делаете, на самом деле не идет по цепочке прототипов - этот вопрос может помочь вам понять, что на самом деле происходит. Я не удосужился проверить спецификацию ECMA, но вот мое мнение по этому вопросу:

  • Функция является конструктором функциональных объектов

  • Function.prototype - это прототип, от которого наследуются все объекты функций - он может содержать такие свойства, как call и apply , которые являются общими для всех Функция экземпляры; проверенные вами реализации были непротиворечивыми в том смысле, что он реализован как сам объект функции (как указывалось some , спецификация ECMA требует этого)

  • Function.prototype.prototype на самом деле не имеет особого смысла, но, поскольку Function.prototype реализован как функциональный объект (который может быть использован как конструктор), он должен хотя бы существовать; объекты, которые создаются с использованием Function.prototype в качестве конструктора, будут наследовать его свойства - но поскольку не должно быть оснований делать что-то безумное, подобное этому, установите для него null , undefined или приемлемый пустой объект

  • Function.prototype.prototype.prototype будет, по всей вероятности, undefined : как мы видели ранее, Function.prototype.prototype должен быть чем-то без свойств ( null , undefined или пустой объект) и определенно не является функциональным объектом; следовательно, его свойство prototype должно быть undefined или может даже выдавать ошибку при попытке доступа

Надеюсь, это поможет;)

4 голосов
/ 20 декабря 2008

Чтобы ответить на ваш вопрос напрямую: Мозилла прав. Не только потому, что Брендан Эйх работает на Mozilla, но и потому, что это единственный правильный способ сделать это. Давайте рассмотрим детали:

  • Каждый конструктор является функцией.
  • Каждая функция имеет prototype свойство, которое будет использоваться для конструирования объектов.
  • Прототип - это объект (словарь). Отдельные объекты делегируют методы / свойства своим соответствующим прототипам.
  • В случае функции объект-прототип является специальным & mdash; он реализует специфичные для функции методы и свойства. Тип / класс этого объекта не определен и не доступен напрямую.
  • Этот объект-прототип не может быть Object или Object.prototype.

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

// we re-creating the function!

// our function constructor
var Fun = function(){ /*...*/ };

// let's chain the prototype
Fun.prototype = new Object();

// do we have a function now? let's fund out
var fun = new Fun();
console.log(fun.length);  // undefined
fun.call(null);           // fail
fun.apply({}, [1, 2, 3]); // fail
// nope

Мы можем заметить, что new Object() не определяет новые методы и свойства и может попытаться использовать Object.prototype напрямую с тем же результатом.

Резюме: прототип функции не Object и не Object.prototype. Это какой-то особенный объект. Это еще одна причина, по которой мы не можем заново создать функцию в коде пользователя.

РЕДАКТИРОВАТЬ: для получения более подробной информации о прототипах посмотрите этот ответ .

2 голосов
/ 22 января 2010

Я знаю, что это сообщение довольно старое, но я искал в сети информацию по этому вопросу и решил, что я опубликую то, что нашел. Свойство prototype предназначено для функций конструктора. Позволяет назначить объект-прототип объектов, которые вы создадите, с новым ключевым словом.

Каждый объект в JavaScript имеет объект-прототип, но многие реализации не дают вам прямого доступа к нему или не позволяют установить его после создания объекта. В FireFox вы можете получить доступ к этому объекту через свойство "__proto__".

Ниже приведена версия вашего кода с использованием свойства "__proto__". Раздел в цепочке прототипов Function соответствует тому, что, как вы думаете, должно было быть.

function nl(z) { document.write(z + "<br>"); }

x = {};

nl(x["__proto__"]);
nl(x["__proto__"] === Object.prototype);

nl("");

nl(nl.prototype.constructor);
nl(nl["__proto__"].constructor);
nl(nl["__proto__"] === nl.prototype);

nl("");

nl(nl["__proto__"]);
nl(nl["__proto__"] === Function.prototype);
nl(nl["__proto__"]["__proto__"] === Object.prototype);
nl(nl["__proto__"]["__proto__"]["__proto__"]);

nl("");

nl(Function["__proto__"]);
nl(Function["__proto__"]["__proto__"]);
nl(Function["__proto__"]["__proto__"] === Object.prototype);
nl(Function["__proto__"]["__proto__"]["__proto__"]);

Вывод в FireFox:

[object Object]
true

function nl(z) { document.write(z + "
"); }
function Function() { [native code] }
false

function () { }
true
true
null

function () { }
[object Object]
true
null
...