JS: копирование метода объекта

170
12 апреля 2018, 13:01
function Rectangle(width,height) {
    this.width = width;
    this.height = height;
    let self = this;
    Rectangle.prototype.getArea = function() {
       return this.height * this.width;
    }
    Object.defineProperty(this, 'getArea', 
       {
          enumerable:true,
          value: function() {
                     return self.height * self.width;
                 }
       }
    );
// this.getArea = function() {
//   return self.height * self.width;
// }
}
 function fromJSON(proto, json) {
     let inp = JSON.parse(json);
     return Object.assign(Object.create(proto),inp);
}
let o = new Rectangle(33,2);
console.log(o);
console.log(o.getArea());
console.log(fromJSON(Rectangle.prototype,'{"width":10,"height":6}'));

В итоге при копировании объекта я получаю два свойства, но метод не передаётся. Что делать, где я не прав? Где почитать?

Я так понимаю, метод получается наследуемым и поэтому не копируется? Его нужно ручками дублировать?

Answer 1

В Вашем коде зачем-то создаются две функции getArea, одна для объекта, который создаётся конструктором, а другая для прототипа.

Первый объект создаётся через конструктор, поэтому имеет и свою функцию, и функцию от прототипа (которая не используется из-за перекрытия первой). Второй объект не создавался через конструктор, а скопировали в него только поля ширины и высоты, поэтому имеет функцию через свой прототип. Вот Ваш код с выводом вызываемых функций:

function Rectangle(width,height) {
    this.width = width;
    this.height = height;
    let self = this;
    Rectangle.prototype.getArea = function() {
       console.log("getArea proto");
       return this.height * this.width;
    }
    console.log('Ctor');
    Object.defineProperty(this, 'getArea', 
       {
          enumerable:true,
          value: function() {
                     console.log("getArea property");
                     return self.height * self.width;
                 }
       }
  );
}
function fromJSON(proto, json) {
     let inp = JSON.parse(json);
     return Object.assign(Object.create(proto),inp);
}
let o = new Rectangle(35,2);
let p = fromJSON(Rectangle.prototype,'{"width":8,"height":6}');
console.log(o.getArea());
console.log(p.getArea());

На выходе имеем подтверждение вышеописанной трактовки:

  • Ctor
  • getArea property
  • 70
  • getArea proto
  • 48

Метод в прототипе

В качестве улучшения, я бы избавился от дублирующего метода, а описание прототипа перенёс бы за пределы конструктора (нам же незачем пересоздавать метод прототипа при каждом вызове конструктора).

function Rectangle(width,height) {
    this.width = width;
    this.height = height;
}
Rectangle.prototype.getArea = function() {
    return this.height * this.width;
};
function fromJSON(proto, json) {
     let inp = JSON.parse(json);
     return Object.assign(Object.create(proto),inp);
}
let o = new Rectangle(35,2);
let p = fromJSON(Rectangle.prototype,'{"width":8,"height":6}');
console.log(o.getArea());
console.log(p.getArea());

Вывод по-сути такой же, а магии в коде меньше:

  • 70
  • 48

Копирование метода объекта, без пртотипа

Можно обойтись и без использования прототипа. Но тогда нужно будет при копировании всегда отталкиваться от какого-то полноценного объекта, который станет аналогом прототипа:

function Rectangle(width,height) {
    this.width = width;
    this.height = height;
    this.getArea = function() {
        return this.width * this.height;
    }; 
}
function fromJSON(proto, json) {
     let inp = JSON.parse(json);
     return Object.assign(Object.create(proto),inp);
}
let o = new Rectangle(35, 2);
let p = fromJSON(o, '{"width":8,"height":6}');
console.log(o.getArea());
console.log(p.getArea());

Вывод такой же:

  • 70
  • 48
READ ALSO
Как настроить анимацию react-burger-menu in react.js

Как настроить анимацию react-burger-menu in react.js

Использую этот https://negomigithub

237
API инстаграма в owlcarousel?

API инстаграма в owlcarousel?

Одно фото попадает в слайдер, все остальные выводятся отдельноПодскажите пожалуйста

118