Это не то, что для собственности .prototype
. Несмотря на название, свойство функций .prototype
на самом деле не является прототипом объектов, с которыми вы привыкли работать. Это одна из самых трудных вещей, чтобы разобраться в JavaScript, так что это не только вы.
Ключ к пониманию прототипа системы в JavaScript является то, что оператор new
создает два объектов, а не один. Я буду говорить об этом в терминах четырех переменных:
-
[[myPrototype]]
-
Прототип объекта. Каждый объект теоретически имеет один (хотя для некоторых объектов он может быть неопределенным).
-
[[Конструктор]]
-
Функция, которая вызывается с новым оператором
-
[[newObject]]
-
Объект, который в конечном итоге будут возвращены
-
[[newPrototype]]
-
Объект, который станет [[newObject]]. [[MyPrototype]]
Обратите внимание, что это недопустимые имена JavaScript (на самом деле, они недопустимые имена в большинстве p языки программирования). Все это происходит за кулисами, и большинство реализаций также не используют эти имена. Я делаю это, чтобы четко указать, что вы обычно не видите эти объекты.
При использовании оператора new
JavaScript выполняет следующие шаги.
- Создать объект [[newPrototype]].
- Set [[newPrototype]]. [[MyPrototype]] to [[Constructor]].prototype
- Создать объект [[newObject]].
- Set [[newObject]]. [[MyPrototype]] в [[newPrototype]]
- Set [[newObject]]. [[MyPrototype]]. Конструктор [[Конструктор]]
- вызов [[ Constructor]], с [[newObject]] как «это».
Обратите внимание, что [[newObject]]. [[MyPrototype]] не идеально подходит для прототипа [[newObject]] или [[Constructor]]. Вот почему нам нужен третий объект между ними: он несет информацию, которую вы хотите наследовать (через [[newPrototype]]. [[MyPrototype]]), но также содержит информацию, специфичную для объекта, который вы создаете (в [ newObject]]. конструктор).
И поэтому мы добираемся до функции .prototype
. Это не функция [[myPrototype]], и это не [[myPrototype]] для создаваемых вами объектов с new
. На самом деле это два уровня в цепочке прототипов, а не один.
Я надеюсь, что это объяснение поможет вам понять, что такое функция .prototype
. Это не простой материал, и не каждое объяснение щелкает со всеми. Это часть того, почему у нас так много объяснений.
При первом создании объекта вы можете установить его прототип напрямую с помощью Object.create()
. Эта функция работает с IE9 и выше (плюс все другие современные браузеры), и ее можно полилизовать, если вам нужно работать со старыми браузерами. Чтобы увидеть этот прототип позже, вы используете Object.getPrototypeOf()
, который также имеет приличную поддержку браузера (хотя IE поддерживает его только в версии 9 и выше). Используя только эти две функции, вы можете создавать свои объекты, как это:
var x = {a:"xa",b:"xb",c:"xc"};
var e = Object.create(x);
x.a = "ea";
x.b = "eb";
console.log(Object.getPrototypeOf(Object));
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);//this is undefined , why? i am expecting it to be "xc"
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
После того, как объект был создан, не стандартный способ сбросить его прототип еще. ECMAScript 6 определяет одно (функция Object.setPrototypeOf()), но пока только Chrome и Firefox поддерживают его: IE и Safari этого не делают. Тем не менее, если это нормально, вы могли бы сделать что-то вроде этого:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(Object.getPrototypeOf(object));
console.log(Object.getPrototypeOf(e));
Object.setPrototypeOf(e, x);
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
Там является нестандартным способом сбросить прототип существующего объекта, и он даже пользуется хорошей поддержкой браузера в настоящее время. Для этого вы устанавливаете свойство .__proto__
на любой стандартный объект. Вы можете использовать его как это:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(object.__proto__);
console.log(e.__proto__);
e.__proto__ = x;
console.log(e.__proto__);
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(e.__proto__.a);
console.log(e.__proto__.b);
Теперь, на ваш последний вопрос: почему Object.prototype
равно {}, а не неопределенными? Поскольку функция конструктора Object
имеет свойство .prototype
, которое становится прототипом по умолчанию всех объектов, созданных через него. Спецификации называют этот объект [[ObjectPrototype]], и в нем живут вещи вроде функции .hasOwnProperty()
.
Вы вводите в заблуждение нормальное свойство '.prototype' с внутренней ссылкой [[prototype]] наследования. – Bergi
Возможно, следующий ответ поможет вам понять прототип: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR