Сегодня мой коллега Xiaoying Children's Shoes задал мне вопрос:
function Foo(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
Foo.prototype.logName = function(){
Foo.combineName();
console.log(this.fullName);
}
Foo.prototype.combineName = function(){
this.fullName = `${this.firstName} ${this.lastName}`
}
var foo = new Foo('Sanfeng', 'Zhang');
foo.logName(); // Uncaught TypeError: Foo.combineName is not a function
Детская обувь Xiaoying думаетFooОбъект-прототипFoo.prototype,такFooунаследуетFoo.prototypeсвойства, звонитеFoo.combineName()эквивалентно вызовуFoo.prototype.combineName(), но результатFoo.combineName()Не метод.
Причина этой проблемы должна заключаться в том, что детская обувь Xiaoying путает некоторые принципы прототипа и наследования.Давайте разберем связанные принципы прототипа и наследования, чтобы выяснить основную причину проблемы.
prototype
prototypeявляется владельцем[[Construct]]Свойства, доступные только для объектов внутренних методов.
Например, функции, методы объектов,ES6класс в . УведомлениеES6Стрелочные функции нет[[Construct]]метод, так что нетprototypeэто свойство, если вы не добавите его для него.
При создании функцииJavaScriptбудет автоматически добавлено для этой функцииprototypeсвойство, это свойство указывает на объект-прототипFunctionname.prototype. Мы можем добавить свойства или объекты к этому объекту-прототипу или даже указать на существующий объект.
__proto__
Далее мы говорим о наследовании, каждый объект имеет__proto__Атрибут, этот атрибут используется для идентификации прототипа, который он наследует.
Уведомление:JavaScriptЛюбой объект имеет встроенное свойство[[Prototype]], до ES5 не было стандартного способа доступа к этому встроенному свойству, но большинство браузеров поддерживают его через__proto__посетить. Используйте следующие равномерно__proto__посетить[[Prototype]], к которым нельзя получить доступ таким образом в фактической разработке.
Сеть прототипов
JavaScriptв состоянии пройтиprototypeа также__proto__Создает связь между двумя объектами, чтобы один объект мог получить доступ к свойствам и функциям другого объекта посредством делегирования.
Одной из таких ассоциаций является цепочка прототипов, конечная цепочка объектов, реализующих наследование и общие свойства.
Конструктор создает экземпляр объекта
JavaScriptФункция имеет два разных внутренних метода:[[Call]]а также[[Construct]].
если не прошелnewключевое слово для вызова функции, а затем выполнить[[Call]]функция, которая непосредственно выполняет тело функции в коде.
когда прошелnewКогда ключевое слово вызывает функцию, выполнение[[Construct]]функция, которая отвечает за создание экземпляра объекта, размещение объекта экземпляра__proto__свойство указывает на конструкторprototypeреализовать унаследованный конструкторprototypeВсе свойства и методы , будутthisПривяжите к экземпляру, а затем выполните тело функции.
Макет конструктора:
function createObject(proto) {
if (!(proto === null || typeof proto === "object" || typeof proto === "function"){
throw TypeError('Argument must be an object, or null');
}
var obj = new Object();
obj.__proto__ = proto;
return obj;
}
var foo = createObject(Foo.prototype);
Пока мы понимаемprototypeа также__proto__Роль , а также понять указатели этих двух свойств при использовании конструктора для создания экземпляра объекта.В следующем изображении показано, как передатьprototypeа также__proto__Реализуйте цепочку прототипов.
Из приведенного выше рисунка мы можем найти, чтоfooобъект иFooЦепочка прототипов функций:
foo.__proto__ == Foo.prototype;
foo.__proto__.__proto__ == Foo.prototype.__proto__ == Object.prototype;
foo.__proto__.__proto__.__proto__ == Foo.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;
Foo.__proto__ == Function.prototype;
Foo.__proto__.__proto__ == Function.prototype.__proto__;
Foo.__proto__.__proto__.__proto__ == Function.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;
КонструкторFooЦепочка прототипов не имеетFoo.prototype, поэтому не может наследоватьFoo.prototypeсвойства и методы на . в то время как экземплярfooцепочка прототипов имеетFoo.prototype,следовательноfooможет быть унаследованFoo.prototypeсвойства и методы на .
На данный момент мы можем легко ответить на вопрос о детской обуви Xiaoying.FooЦепочка прототипов не имеетFoo.prototype, который не может быть унаследованFoo.prototypeВверхcombineNameметод, таким образом бросаяFoo.combineName is not a functionисключение. использоватьcombineNameметод, поэтомуFoo.prototype.combineName.call(this), или вот такthis.combineName()(thisк объекту экземпляра).
Добро пожаловать, чтобы следовать:Leechikit
Оригинальная ссылка:segmentfault.comВ конце статьи приветствуются вопросы и исправления. Писать оригинальные статьи непросто, если эта статья была вам полезна, ставьте лайки, рекомендуйте и подписывайтесь на автора для поддержки.