Свойства и методы прототипа и экземпляра в javascript

3

Prototype vs Instance Members (Элементы прототипа vs элементы экземпляра)

function Circle(radius) {
    this.radius = radius;

    this.draw = function() {
        console.log('draw');
    }
}

const c1 = new Circle(1);
const c2 = new Circle(1);

Есть у нас допустим функция-конструктор, у которой две проперти: свойство и метод. А также у нас есть два circle объекта. Давайте посмотрим на них в devtools.

При данной реализации, если у нас допустим тысяча circle объектов в памяти, то у нас будет 1000 копий метода draw. Обычно в реальных приложениях у наших объектов более чем один метод, и при данных условиях, копии их методов будут забивать память.

И как же быть?

Итак, мы знаем как работает прототипное наследование, когда мы пытаемся обратиться к свойству или методу объекта, движок javascript сначала пытается найти эти херни в самом объекте. Если он не может найти их в объекте, то пытается нати их в прототипе объекта.

Поэтому мы можем взять этот метод draw и внести его в prototype объекта.

У нас будет один экземпляр этого прототипа в памяти, который мы называем базовым Circle. У нас будет только один экземпляр метода draw.

У каждого конструктора есть свойство prototype.
И он точно такой же как прототип объекта сконструированного этим конструктором. Они ссылаются на один и тот же объект — Circle base.

Circle.prototype === c1.__proto__; //true

Итак, мы знаем что объекты в JavaScript динамические и мы можем добавлять в них что захотим когда захотим.

Таким образом, мы можем добавить метод draw в наш прототип.

Circle.prototype.draw = function () {
    console.log('draw');
}

И теперь мы можем спокойно убрать метод draw из нашего конструктора.

Теперь мы можем посмотреть на один из наших объектов в консоли и увидим наш метод draw в его прототипе. По сути у нас есть два типа свойств и методов в javascript:

  • Insctance members — свойства и методы экземпляра
  • Prototype members — свойства и методы прототипа

Итак, мы знаем, что у всех объектов есть доступ к методу toString(). И по умолчанию он выдает строку с хернёй.

Но мы можем изменить реализацию этого метода. Например у наших circle объектов.

Выведем фразу: Circle with radius и выведем сам радиус объекта через this.radius;

Circle.prototype.toString = function () {
    return `Circle with radius ${this.radius}`;
}

Теперь, когда мы вызываем c1.toString() то получим Circle with radius 1.

Итак, согласно прототипному наследованию, когда мы обращаемся к этому методу, то движок javascript сначала пытается найти его в самом circle объекте, и если не находит, то смотрит в прототипе объекта. Так как мы его там имплементировали, то очевидно, что он находит его в прототипе. И он воспользуется им.

В чём сахар. Даже если у нас есть другая реализация toString метода в базовом объекте, но будет использоваться наша, потому что доступна первее.

И помните, что при любом типе свойств и методов, будь то экземпляра или прототипа, мы можем ссылаться на другие элементы объекта, Например
в методе прототипа draw мы можем легко вызвать метод экземпляра, который находится в Circle классе. И в тоже время мы можем в методе экземпляра использовать метод прототипа.

function Circle(radius) {
    this.radius = radius;

    this.move = function() {
        this.draw();
        console.log('move');
    }
}

Circle.prototype.draw = function () {
    this.move();
    console.log('draw);
}

You might also like More from author

Leave A Reply

Your email address will not be published.