конструктор и прототип - PullRequest
3 голосов
/ 26 февраля 2012

Может кто-нибудь объяснить это?

function Foo() {
    this.x = 1;
    this.y = 2;
}

function FooProto() {
    this.arrow = 1;
    this.bow = 1;
}

document.writeln(Foo.prototype); // [object Object] 
document.writeln(Foo.prototype.constructor); // function Foo() { x =1; y=2; }

Мое понимание здесь таково: Foo.prototype - это объект, свойство конструктора которого - функция Foo.Foo. [[Prototype]] - это Function.Prototype

obj = new Foo;
document.writeln(obj.constructor); // function Foo() { x =1; y=2; }
document.writeln(obj.constructor.prototype); // [object Object]

Foo.prototype = FooProto;

document.writeln(Foo.prototype); // function FooProto() { arrow = 1; bow = 2; }
document.writeln(Foo.prototype.constructor); // function Function() { [native code] }

Вопрос 1: Как происходил поиск с использованием [[Prototype]].Буду признателен, если кто-нибудь сможет мне это объяснить.

document.writeln(obj.constructor); // function Foo() { x =1; y=2; } .. no change
document.writeln(obj.constructor.prototype); // function FooProto() { arrow = 1; bow = 2; }

anotherObj = new Foo;
document.writeln(anotherObj.constructor); // function Function() { [native code] }
document.writeln(anotherObj.constructor.prototype); // function Empty() {}

Вопрос 2: Тот же вопрос, что и в вопросе 1. Как интерпретатор Javascript выполнил поиск?

Ответы [ 2 ]

5 голосов
/ 26 февраля 2012

При объяснении кода на основе прототипов гораздо проще использовать Object.create для объяснения вещей.Object.create - это функция, которая получает объект-прототип и создает новый объект-экземпляр, который имеет объект-прототип в качестве [[prototype]]

Когда поиск свойств в объекте работает следующим образом:

Каждый объект имеет свое собственное и неизменное свойство [[prototype]] внутри.Это свойство является секретным и скрытым, если вы не находитесь в Firefox, где вы можете получить его через __proto__.

Когда читает свойство вверх, мы сначала ищем его в самом объекте иесли мы не найдем его там, мы рекурсивно ищем [[prototype]] объекта.

Когда записывает свойство, мы всегда пишем свое собственное свойство (мы никогда не изменяем [[прототип]], даже если он также имеет свойство, которое мы устанавливаем).

proto = {a:1};
child1 = Object.create(proto);
child2 = Object.create(proto);

child1.a = 2;

console.log(proto.a);  //1
console.log(child1.a); //2
console.log(child2.a); //1

При создании функции

Всякий раз, когда мы создаем объект функции в Javascript,он поставляется с уже заполненным свойством prototype. Этот prototype является объектом (унаследованным от Object.prototype) и имеет свойство constructor, установленное на соответствующую функцию.

При создании экземпляраобъект, использующий конструктор функции (новый Foo)

Создается новый объект с функциями prototype в качестве [[prototype]] и запускается функция объекта для его инициализации.


  1. I dна самом деле не хочу объяснять, что происходит в первом случае, поскольку часть Foo.prototype = FooProto; не имеет никакого смысла и, вероятно, не то, что вы хотели сделать (помните, что прототипы должны быть объектами, а не функциями)

  2. Что касается второго случая, изменение свойства prototype функции конструктора повлияет только на будущие экземпляры (anotherObj).Свойство [[prototype]] уже созданных объектов является секретным и неизменным, поэтому вы ничего не можете сделать, чтобы изменить их.

    • Обратите внимание, что если вы хотите динамически изменить прототип и существующие объекты (это можно сделать, записав и перезаписав значения в существующем объекте-прототипе вместо его замены новым.
0 голосов
/ 06 октября 2014

В Javascript есть две концепции прототипа.(Я воспринимаю это как столкновение имен в дизайне языка.)

  1. Прототип в " цепочке прототипов ".Это внутреннее свойство, как упоминалось в последнем ответе.Предпочтительный способ доступа к нему - Object.getPrototypeOf.

    var a = {};
    Object.getPrototypeOf(a); // Object {}
    Object.getPrototypeOf(Object.getPrototypeOf(a)); // null, the top of prototype chain.
    Object.getOwnPropertyNames(Object.getPrototypeOf(a)); // the methods inherited
    
  2. Каждый конструктор (я думаю, что фактически каждая объявленная функция) имеет собственное свойство "prototype".Он используется в операторе new.

Оператор new делает 2 шага.

  1. Первый - создать объект, прототип которого (1-й, например, [[Prototype]]) назначен в качестве прототипа конструктора (2-й).
  2. Второй - запустить конструктор (взглянув на prototype.constructor), приняв созданный объект в качестве неявного аргумента this.

Теперь к вашему случаю:

Первый obj был создан с его свойством [[Prototype]] ( proto в некоторых движках), назначенным как Foo.prototype.

obj.constructor === obj.__proto__.constructor === Foo.prototype.constructor === Foo
obj.constructor.prototype === Function.prototype

Обратите внимание, что конструктор также является объектом Function.

Затем вы изменили прототип Foo.Это изменило obj.constructor.prototype, но не obj.constructor, который имеет другую ссылку.У anotherObj появился новый [[Prototype]] из следующего оператора new.

Этот вопрос был здесь уже много лет.Следующие читатели могут быть также смущены как я.Я рекомендовал недавно опубликованную книгу Speaking JavaScript от доктора Акселя Раушмайера:

Терминология: два прототипа

...