Функция конструктора 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();
Мое понимание этого кода:
- JS создает новый экземпляр объекта Animal, на который указывает var dog в результате использования ключевого слова new перед вызовом функции
Animal()
- конструктор функции - Прототип объекта var dog имеет
sayName()
метод, прикрепленный к нему в строке:Animal.prototype.sayName = function()
- Так как
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, которые вызывают много путаницы:
- это единственная динамическая встроенная функция языка
- это рассматривается как неявный параметр
Лексическая область
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