Функция конструктора JavaScript, метод присоединения прототипа и 'this'

Я работаю с упражнениями CodeAcademy JS и у меня есть вопрос об этом примере:

//Animal class
function Animal(name) {
    this.name = name;
}

//Attach sayName method to Animal class
Animal.prototype.sayName = function() {
    console.log("Hi my name is " + this.name);
};

//create an animal object instance
var dog = new Animal('Barker');

//invoke a method attached to the prototype from the object instance
dog.sayName();

Мое понимание этого кода:

  1. JS создает новый экземпляр объекта Animal, на который указывает var dog в результате использования ключевого слова new перед вызовом функции Animal() - конструктор функции
  2. Прототип объекта var dog имеет sayName() метод, прикрепленный к нему в строке: Animal.prototype.sayName = function()
  3. Так как sayName() был прикреплен к классу prototype, метод теперь доступен для любых объектов, созданных из Animal класс через использование new Animal() конструктор функций

Это правильное понимание того, что происходит с этим кодом?

Кроме того, я пытаюсь понять, как this указывает на объект Animal в this.name:

Animal.prototype.sayName = function() {
    console.log("Hi my name is " + this.name);
};

не Animal.prototype указать на реальный объект: prototype объект этого Animal экземпляр объекта? Если это так, не должен this в this.name указать на Animal.prototype, поскольку sayName() на самом деле вызывается из Animal.prototype?

Мое понимание контекста для this в том, что this всегда указывает на объект, который вызывает функцию. Однако в этом случае, когда dog.sayName() вызывается, this указывает на Animalчто как this.name равняется 'Barker' когда он вошел в консоль. Я предполагаю, что либо я неправильно понимаю, что Animal.prototype указывает на объект-прототип, либо JS делает что-то "за кулисами", чтобы связать dog.sayName() в this в контексте присоединения метода к prototype,

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

3 ответа

Решение

[пункты 1-3]

Это правильное понимание того, что происходит с этим кодом?

Да, звучит так, будто ты это понимаешь.

Разве Animal.prototype не указывает на реальный объект: prototype объект этого Animal экземпляр объекта?

Да, prototype объект является Object пример.

Если это так, не должен this в this.name указать на Animal.prototype, поскольку sayName() на самом деле вызывается из Animal.prototype?

Нет, потому что вы назвали это как метод dog,

dog.sayName();

Если бы вы назвали это так, то да, this сослался бы на Animal.protoype,

Animal.protoype.sayName();

Но это было бы не очень полезно.

Мое понимание контекста для this в том, что this всегда указывает на объект, который вызывает функцию.

Не совсем. По большей части this относится к объекту, к которому был вызван метод, а не к объекту, к которому он принадлежит. Метод на самом деле может быть свойством нескольких объектов, поэтому this динамически указывает на объект, который он был назван как метод.

Конечно, this может ссылаться на другие вещи в других контекстах, например, когда не вызывается как метод, или в связанной функции, используя .bind,

this имеет два отличительных признака в Javascript, которые вызывают много путаницы:

  1. это единственная динамическая встроенная функция языка
  2. это рассматривается как неявный параметр

Лексическая область

var i = 0;
const inc = () => i + 1;

const inc2 = x => {
  var i = x;
  return inc();
};

inc2(100); // 1

Динамическая область

var o = {
  i: 0,
  inc: function () { return this.i + 1 }
};

var p = {
  i: 100,
  inc2: o.inc
};

p.inc2(); // 101

this динамически ограничен, потому что это установлено через контекст вызова.

Неявный параметр

Вместо прохождения this явно как формальный параметр для методов, это трактуется неявно. Следовательно, вам нужно использовать call/apply установить разные значения (а именно объекты) для this:

// Note that s and t are implicitly converted to objects

const split = (o, x) => o.split(x);
let s = "1,2,3", t = "4,5,6";

// objects are passed explicitly as normal arguments
split(s, ","); // ["1", "2", "3"]
split(t, ","); // ["4", "5", "6"]

// objects (or this) are provided implicitly
s.split(","); // ["1", "2", "3"]
s.split.call(t, ",") // ["4", "5", "6"]

Представить this как принимающий объект метода, который должен быть передан в качестве первого параметра.

Ты не понял this, Значение this не устанавливается при создании функции, это дополнительный аргумент. Каждый раз, когда вы вызываете функцию, this значение может измениться.

В случае методов, this значение устанавливается для базового объекта. Например,

dog.sayName(); // `this` is `dog`
({sayName: dog.sayName}).sayName(); // `this` is this new object
(0,dog.sayName)(); // `this` is undefined or the global object
Другие вопросы по тегам