Object.getPrototypeOf() vs.prototype
Я изучаю JS, и я надеюсь, что кто-то может объяснить мне, в упрощенном виде, разницу между Object.getPrototypeOf()
vs .prototype
function ParentClass() {}
function ChildClass() {}
ChildClass.prototype = new ParentClass();
var mychild = new ChildClass();
var myparent = new ParentClass();
# .getPrototypeOf
Object.getPrototypeOf(ChildClass.prototype) // ParentClass {}
Object.getPrototypeOf(mychild) // ParentClass {}
Object.getPrototypeOf(ParentClass.prototype) // {}
Object.getPrototypeOf(myparent) // ParentClass {}
# .prototype
ParentClass.prototype // ParentClass {}
myparent.prototype // undefined
ChildClass.prototype // ParentClass {}
mychild.prototype // undefined
Похоже, вы можете только вызывать.prototype на конструкторе?
Есть ли другие отличия?
Ответы
Ответ 1
TL; DR
function MyConstructor() {}
var obj = new MyConstructor()
Object.getPrototypeOf(obj) === obj.prototype // false
Object.getPrototypeOf(obj) === MyConstructor.prototype // true
MyConstructor.prototype // MyConstructor {}
obj.prototype // undefined
MyConstructor.prototype.constructor === MyConstructor // true
Object.getPrototypeOf(MyConstructor) === Function.prototype // true
Запутанная часть о прототипах в javascript заключается в том, что есть 2 разные вещи, которые звучат очень похоже.
Когда вы создаете новый объект, если у функции или объекта, использованного для создания нового объекта, есть метод .prototype, то объект, на который ссылается .prototype
, станет прототипом нового объекта newObj.__proto__
.
Звучит сложно... давай разберемся дальше.
A. Свойство .prototype
Пример - Использование функции в качестве конструктора
Когда вы используете ключевое слово new
для функции (т.е. вы используете функцию в качестве конструктора), тогда функция .prototype становится новым obj.__proto__
.
Давайте сначала создадим функцию и извлечем это свойство .prototype
function MyConstructor(){
}
console.log(MyConstructor.prototype) // {}
Подождите... MyConstructor.prototype//{}
- что-то волшебным образом случилось? Откуда появился этот пустой объект {}
?
2 вещи здесь:
-
Javascript автоматически создает объект .prototype всякий раз, когда вы объявляете функцию - автоматически.
-
Этот объект не пуст. На самом деле у него есть свойство, которое указывает на функцию, которая создала объект (объект "конструктор"). Позвольте проверить это:
console.log(MyConstructor.prototype.constructor);//[Function: MyConstructor]
MyConstructor.prototype.constructor === MyConstructor//true
Поэтому для функций свойство .prototype и связанный с ним объект создаются автоматически.
Все еще в замешательстве? Давайте добавим несколько методов, чтобы было легче увидеть, что происходит...
function MyConstructor(){
}
MyConstructor.prototype.func2 = function(){
};
console.log(MyConstructor); // [Function: MyConstructor]
console.log(MyConstructor.prototype); // MyConstructor { func2: [Function] }
MyConstructor.func2(); // TypeError: MyConstructor.func2 is not a function
Из приведенного выше кода ясно видно, что MyConstructor и MyConstructor.prototype являются двумя отдельными объектами.
Б. Прототип объекта
Прототип объекта (не .prototype - см. A. выше) - это то, что javascript использует для поиска и разрешения методов, которых еще нет в объекте (подробнее об этом позже).
Продолжая выше, когда мы создаем объект из функции или объекта, который имеет свойство .prototype, у вновь созданного объекта будет его object.__proto__
ссылающийся на этот объект .prototype.
Прототип объекта доступен
Object.getPrototypeOf(obj)
или устарел
obj.__proto__
Пример - Использование функции в качестве конструктора
Давайте создадим новый объект, используя функцию MyConstructor в качестве конструктора.
function MyConstructor(){
}
var obj = new MyConstructor()
console.log(Object.getPrototypeOf(obj)); // {}
Вот три важные вещи:
- MyConstructor (функция)
- obj (объект, который был создан из MyConstructor)
-
obj.__proto__
→ MyConstructor.prototype
Итак, obj.__proto__
- это MyConstructor.prototype
. Вот доказательство:
MyConstructor.prototype === Object.getPrototypeOf(obj) // true
Давайте добавим метод в MyConstructor
function MyConstructor(){
this.func1 = function(){
console.log("this is func1");
};
}
var obj = new MyConstructor();
obj.func1(); // this is func1
Из приведенного выше видно, что вы можете вызывать методы, которые были объявлены в конструкторе. На самом деле, если мы посмотрим, наш объявленный метод func1 фактически является частью obj из-за того, как javascript создает объекты.
console.log(obj); // MyConstructor { func1: [Function] }
Мы также можем добавить методы, которые obj может использовать, добавив методы в прототип. например
MyConstructor.prototype.func2 = function(){
console.log("this is func2");
};
obj.func2(); // this is func2
Методы MyConstructor и MyConstructor.prototype будут доступны для всех объектов, созданных с использованием MyConstructor с использованием этой настройки.
Полезные ссылки
Полное руководство по объектно-ориентированному JavaScript
Понимание JavaScript: наследование и цепочка прототипов
Простой английский путеводитель по прототипам JavaScript
Ответ 2
function Foo() {
// ...
}
var a = new Foo();
Object.getPrototypeOf( a ) === Foo.prototype; // true
Когда a
создается путем вызова new Foo()
, одна из вещей, которая происходит, заключается в том, что a
получает внутреннюю ссылку [[Prototype]]
к объекту, на который Foo.prototype
.
Я предлагаю вам прочитать книгу "Вы не знаете JavaScript", если вы действительно хотите подробно изучить JavaScript.
Ответ 3
Object.getPrototypeOf()
против .prototype
-
Prototype
: у каждого объекта в JavaScript есть прототип. Это просто еще один объект, от которого он "наследует" свойства и методы. Эта концепция называется наследованием прототипов и является единственной формой наследования, которая существует в javascript. Такие конструкции, как ключевое слово class
в javascript, являются просто синтаксическим сахаром, построенным поверх этой системы наследования прототипов.
Каждая функция имеет свойство объекта- prototype
. Когда эта функция затем используется в качестве функции конструктора с new
ключевым словом, вновь созданный объект будет наследоваться от этого объекта- prototype
.
-
Object.getPrototypeOf()
: является функцией, которая возвращает ссылку на этот объект-прототип. Мы передаем объект в качестве аргумента, и он вернет ссылку на объект-прототип.
Пример:
function Dog (name) {
this.name = name;
}
// We can put properties on the prototype of the Dog constructor
Dog.prototype.bark = function () { console.log('woof'); };
let dog = new Dog('fluffie');
// Our newly created dog now has access to this bark method via the prototype chain
dog.bark();
// With the Object.getPrototypeOf method the Dog prototype object is returned
console.log(Object.getPrototypeOf(dog));
Ответ 4
Прототип - это механизм, с помощью которого объекты JavaScript наследуют функции друг от друга. [1]
Object.getPrototypeOf
- возвращает прототип заданного объекта. [2]
Следующий код определяет функцию конструктора, которую можно использовать для создания объектов, поместив ключевое слово new
перед его вызовом:
function Cat(name) {
this.name = name;
}
Cat.prototype.meow = function (sound) {
console.log('Meow ${sound}');
};
let cat = new Cat("Garfield");
Конструкторы автоматически получают свойство с именем prototype
, которое по умолчанию содержит простой пустой объект, производный от Object.prototype
. Это свойство может быть переопределено, или вы также можете добавить свойства, как в предыдущем коде.
Крайне важно понять различие между тем, как прототип связан с конструктором (через его свойство prototype), и тем, как объекты имеют прототип (который можно найти с помощью Object.getPrototypeOf).
Фактическим прототипом конструктора является Function.prototype
поскольку конструкторы являются функциями. Его свойство prototype содержит прототип, используемый для экземпляров, созданных через него.
Надеемся, что в этот момент следующий код оставит ясным то, что было сказано ранее:
// This is a Cat object
> cat
Cat {name: "Garfield"}
> cat.prototype // notice that this object does not have the prototype property
undefined
// this is the constructor function
> Cat
ƒ Cat(name) {
this.name = name;
}
// this is the prototype property of a constructor
> Cat.prototype
{meow: ƒ, constructor: ƒ}
meow: ƒ (sound)
constructor: ƒ Cat(name)
__proto__: Object
// this is true as previously stated
> Object.getPrototypeOf(Cat) == Function.prototype
true
// this is true since the property prototype of a constructor is the
// prototype that objects created from it will have
> Object.getPrototypeOf(cat) == Cat.prototype
true
// Finally the prototype of the prototype property of a constructor
// is the same as Object.prototype
> Object.getPrototypeOf(Cat.prototype) == Object.prototype
true
Дополнительная информация
JS-классы, представленные в ES6, в основном являются синтаксическим сахаром по сравнению с существующим наследованием на основе прототипов JavaScript. Синтаксис класса не вводит новую объектно-ориентированную модель наследования в JavaScript.
Итак, предыдущее определение Cat
эквивалентно следующему:
class Cat {
constructor(name) {
this.name = name;
}
meow(sound) {
console.log('Meow ${this.sound}');
}
}
Ответ 5
@lukeaus ответ превосходен. Для меня наиболее важными моментами являются:
- Свойство .prototype функции НЕ совпадает с прототипом функции.
- Свойство .prototype указывает прототип объектов, созданных из функции.
function MyConstructor() {} // automatically creates MyConstructor.prototype
// You can add methods to MyConstructor.prototype for objects to "inherit"
MyConstructor.prototype.foo = function() { console.log("do foo") }
// Or even reassign .prototype
// MyConstructor.prototype = { foo: function() { console.log("more foo?") } }
var obj = new MyConstructor()
Object.getPrototypeOf(obj) === MyConstructor.prototype // true
obj.foo()
Таким образом, прототипом объекта является MyConstructor.prototype. Какой прототип MyConstructor? Ну, каждая функция "наследует" от Function, поэтому Object.getPrototypeOf(MyConstructor) === Function.prototype
Как примечание: все становится странным, если вы назначаете .prototype чему-то глупому, например:
function MyConstructor() {}
MyConstructor.prototype = "foo" // make objects inherit from... a string?
var obj = new MyConstructor()
Object.getPrototypeOf(obj) === MyConstructor.prototype // false!
Ответ 6
Там только одно отличие, метод Object.getPrototypeOf
получает конструктор объекта, а затем возвращает его прототип, в то время как свойство prototype
ничего не делает (возвращает себя). (Ну, prototype
может быть любым, но если его объектом является класс, prototype
безусловно, должен быть объектом.).