Почему объекты JavaScript не получают копию данных и методов в ES6

Одним из общих аспектов объектно-ориентированного проектирования (в большинстве языков, особенно в Java) является то, что когда мы создаем новый объект с помощью конструктора, все методы и общедоступные/защищенные переменные экземпляра копируются в объект. Например:

Car myCar = new Car('Corolla', '2015');

Теперь, если класс Car имеет методы goForward() или goBackward(), все они будут скопированы в объект myCar.

Но это не так в JavaScript, пока я его изучал. Если это было похоже на JavaScript, myCar имел прототип, который на самом деле указывает на прототип Car.

Насколько я понимаю, это копирование данных и методов является высшим требованием, если мы хотим использовать наследование классов в качестве шаблона проектирования. Действительно ли в JavaScript отсутствует эта функция, или я просто не понимаю? Привносит ли новая структура на основе классов ES6 эту вещь в картину?

Спасибо за разъяснение моих концепций, я очень запутался в этом, так как в прошлом я делал что-то на Java.


person shahzaibkhalid    schedule 02.09.2017    source источник
comment
Я не совсем понимаю вопрос. В большинстве языков ООП, когда вы создаете новый экземпляр класса, методы не копируются в него, просто устанавливается класс объекта, и когда вы вызываете метод, есть механизм для поиска его в связанном классе и его суперклассах. Это работает так же в javascript, просто у вас есть прототип вместо класса. Классы ES6 — это просто синтаксический сахар, это эквивалентно выполнению new Car(...) в чистом JS.   -  person Mario F    schedule 03.09.2017
comment
Взгляните на stackoverflow.com/questions/572897/ - действительно ваше понимание кажется слишком расплывчатым. Ни в одном серьезном ООП-языке каждый метод копируется в каждый экземпляр: в Java компилятор творит чудеса, позволяя вам вызывать myCar.goBackward(), а в JavaScript это полностью прозрачная конструкция времени выполнения, которая позволяет вам делать myCar.goBackward(). Это никак не влияет на дизайн, просто становится более гибким.   -  person Bergi    schedule 03.09.2017
comment
Нет, ES6 class не приносит новую структуру, а только новый синтаксис — концепция работы наследования не изменилась.   -  person Bergi    schedule 03.09.2017


Ответы (1)


В Javascript функция-конструктор содержит свойство .prototype, которое содержит любые методы, определенные для этого объекта (либо с прямым присвоением прототипу в ES5, либо с ключевым словом class в ES6).

Затем, когда вы создаете экземпляр нового объекта с помощью этого конструктора, объект получает указатель на прототип. Когда для этого объекта вызывается метод, интерпретатор Javascript сначала ищет в самом объекте свойство с таким именем и, если не находит там, затем переходит к поиску в цепочке прототипов.

Итак, единственное, что «копируется» во вновь созданный объект в Javascript, — это указатель на прототип. И это работает одинаково в ES5 и ES6. Синтаксис class в ES6 — это просто новый синтаксис для выполнения того, что мы уже делали вручную в ES5 (назначение методов объекту-прототипу).

На самом деле, вы даже можете получить прототип, если хотите, с помощью Object.getPrototypeOf(). Важно понимать, что новый объект содержит указатель на объект-прототип (а не копию). Если в объект-прототип вносятся последующие изменения, он становится «живым», и все объекты, созданные до или после, увидят это изменение.

class Car {
    constructor(brand, model) {
        // initialize instance data
        this.brand = brand;
        this.model = model;
    }
    goForward() {
        console.log("goForward");
    }
    goBackward() {
        console.log("goBackward");
    }
}

let c = new Car("Toyota", "Corolla");
console.log(Object.getPrototypeOf(c));    // shows the two methods goForward, goBackward
console.log(c.brand);      // "Toyota"

Теперь, если в классе Car есть методы goForward() или goBackward(), все они будут скопированы в объект myCar.

Новому объекту дается указатель на прототип. Методы не копируются по отдельности.

Насколько я понимаю, это копирование данных и методов является высшим требованием, если мы хотим использовать наследование классов в качестве шаблона проектирования.

Это просто неправда. Наследование не требует копирования всех методов в новый объект. На самом деле существует много разных способов добиться правильного наследования. Javascript использует прототип. C++ использует привязку времени компиляции. Я сам не знаю внутренностей Java, но этот пост относится к таблица методов, на которую каждому объекту в Java дается указатель.

Привносит ли новая структура на основе классов ES6 эту вещь в картину?

ES6 не меняет того, как наследование работает внутри Javascript. ES6 просто вводит синтаксис class, который представляет собой другой способ объявления конструктора объекта и методов, но приводит к той же внутренней структуре, что и способ, которым мы вручную объявляли методы в прототипе в ES5.

person jfriend00    schedule 02.09.2017