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 вещи здесь:

  1. Javascript автоматически создает объект .prototype всякий раз, когда вы объявляете функцию - автоматически.

  2. Этот объект не пуст. На самом деле у него есть свойство, которое указывает на функцию, которая создала объект (объект "конструктор"). Позвольте проверить это:

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 безусловно, должен быть объектом.).