Попытка согнуть голову вокруг взятия Javascript на OO … и, как и многие другие, сталкивается с путаницей в отношении constructor Что-нибудь из constructor Билл, я смею ответить на твой вопрос, однако я не уверен на 100 % в своих догадках. Я думаю, что другие браузеры IE при переносе пользователя на страницу в истории не только загрузят страницу и ее ресурсы из кэша, но и восстановят для нее все состояние DOM (чтение сеанса). IE не выполняет восстановление DOM (или не сдавал в аренду), и, таким образом, событие onload кажется необходимым для правильной повторной инициализации страницы.

function Foo(age) {
    this.age = age;
}

function Bar() {
    Foo.call(this, 42);
    this.name = "baz"; 
}

Bar.prototype = Object.create(Foo.prototype); 
var b = new Bar;    

alert(b.constructor); // "Foo". That's OK because we inherit `Foo`'s prototype.
alert(b.name);        // "baz". Shows that Bar() was called as constructor.
alert(b.age);         // "42", inherited from `Foo`.

В приведенном выше примере, Кажется, у объекта b был правильный конструктор (Bar) — и он наследует свойство age от Foo. Итак, почему многие люди предлагают это как необходимый шаг:

Bar.prototype.constructor = Bar;

Очевидно, право Bar Конструктор была вызывается при построении b, так какое влияние оказывает это свойство прототипа? Мне любопытно узнать, какое практическое значение имеет то, что свойство конструктора установлено «правильно», поскольку я не вижу, чтобы это каким-либо образом влияло на то, какой конструктор фактически вызывается после создания объекта. Свойство

Переменная constructor абсолютно ничего не меняет внутри. Это только для использования, если ваш код явно использует его. Например, вы можете решить, что каждый из ваших объектов должен иметь ссылку на фактическую функцию конструктора, которая его создала ;, если это так, вам необходимо явно установить свойство constructor, когда вы устанавливаете наследование с помощью присвоение объекта свойству функции конструктора prototype, как в вашем примере.

Первый шаг — понять, что такое constructor и prototype. Это не сложно, но нужно отказаться от «наследования» в классическом смысле.

Конструктор

Переменная constructor flexbox: не вызывает любые специфические эффекты в вашей программе, за исключением того, что вы можете посмотреть на него, чтобы увидеть, какая функция использовалась вместе с оператором new для создания вашего объекта. Если вы ввели new Bar(), это будет Bar, а вы ввели new Foo Это будет Foo Глядя на вывод

Свойство prototype

Переменная prototype используется для поиска в случае, если у рассматриваемого объекта нет запрошенного свойства. Если вы напишите x.attr, JavaScript попытается найти attr среди атрибутов x. Если он не может найти его, он будет выглядеть в x.__proto__. Если его там тоже нет, он будет смотреть в x.__proto__.__proto__ и так далее, пока определено __proto__.

. Так что же такое __proto__ и какое это имеет отношение к prototype? Коротко говоря, prototype для «типов», а __proto__ для «экземпляров». (Я говорю это с кавычками, потому что на самом деле нет никакой разницы между типами и экземплярами). Когда вы пишете x = new MyType(), то происходит (среди прочего), что x.__proto___ устанавливается на MyType.prototype Глядя на вывод

. Вопрос

Теперь, все вышеперечисленное должно быть всем, что вам нужно, чтобы получить то, что означает ваш собственный пример, но попытаться и ответьте на ваш настоящий вопрос ; «зачем писать что-то вроде»:

Bar.prototype.constructor = Bar;

Лично я никогда не видел это и считаю это немного глупым, но в контексте, который вы дали, это будет означать, что Bar.prototype — объект (созданный с помощью new Foo(42) ) будет выглядеть как созданный Bar, а не Foo. Я предполагаю, что идея состоит в том, чтобы сделать что-то похожее на C / Java / C # — подобные языки, где поиск по типу (свойство constructor) всегда будет давать наиболее конкретный тип, а не тип более родовой объект далее в цепочке прототипов.

Мой совет: не думайте особо о «наследовании» в JavaScript. Концепции интерфейсов и микшинов имеют больше смысла. И не проверяйте объекты на предмет их типов. Вместо этого проверьте требуемые свойства («если он ходит как утка и крякает как утка, это утка»).

Попытка ввести JavaScript в классическую модель наследования, когда все, что у него есть, это механизм-прототип, как описано выше, и вызывает путаницу. Многие люди, которые предлагали вручную установить свойство constructor -, вероятно, пытались сделать именно это. Абстракции хороши, но это ручное присвоение свойства конструктора не очень идиоматическое использование JavaScript.

один случай использования конструктора:

  1. это одна из распространенных реализаций наследования:

    Function.prototype.extend = function(superClass,override) {
        var f = new Function();
        f.prototype = superClass.prototype;
        var p = this.prototype = new f();
        p.constructor = this;
        this.superclass = superClass.prototype;
        ...
    };
    
  2. this new f() не будет вызовите конструктор superClass, поэтому при создании подкласса может потребоваться сначала вызвать superClass, например, так: свойство

    SubClass = function() {
        SubClass.superClass.constructor.call(this);
    };
    

Почему бы не использовать это? Это не прокручивает страницу вверх.

Другое отличие, которое не упомянуто в других ответах, состоит в том, что если вы используете анонимную функцию prototype.constructor для выживания prototype переназначение свойства происходит, когда вы определяете метод в prototype, который создает новый экземпляры того же типа, что и данный экземпляр. Пример:

function Car() { }
Car.prototype.orderOneLikeThis = function() {  // Clone producing function
    return new this.constructor();
}
Car.prototype.advertise = function () {
    console.log("I am a generic car.");
}

function BMW() { }
BMW.prototype = Object.create(Car.prototype);
BMW.prototype.constructor = BMW;              // Resetting the constructor property
BMW.prototype.advertise = function () {
    console.log("I am BMW with lots of uber features.");
}

var x5 = new BMW();

var myNewToy = x5.orderOneLikeThis();

myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not 
                      // commented; "I am a generic car." otherwise.

Свойство конструктора указывает на конструктор, который использовался для создания экземпляра объекта. Если вы ввели ‘new Bar ()’, это будет ‘Bar’, а вы ввели ‘new Foo ()’, это будет ‘Foo’.

Но если вы установите прототип без установки конструктора, вы получите что-то вроде этого:

function Foo(age) {
    this.age = age;
}

function Bar() {
    this.name = "baz"; 
}

Bar.prototype = new Foo(42); 
var one = new Bar();
console.log(one.constructor);   // 'Foo'
var two = new Foo();
console.log(two.constructor);   // 'Foo'

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

function Foo(age) {
    this.age = age;
}

function Bar() {
    this.name = "baz"; 
}

Bar.prototype = new Foo(42); 
Bar.prototype.constructor = Bar;
var one = new Bar();
console.log(one.constructor);   // 'Bar'
var two = new Foo();
console.log(two.constructor);   // 'Foo'