Конструктор и наследование свойств от суперкласса в javascript - PullRequest
0 голосов
/ 13 июля 2020

У меня вопрос по поводу кода, демонстрирующего наследование в javascript. Код основан на https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

Здесь вы можете увидеть живую демонстрацию: https://jsfiddle.net/gk6xar8w/3/

Вот код:

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 2); // Outputs, 'Shape moved. 2, 4'
rect.move(1, 2); // Outputs, 'Shape moved. 3, 6'

У меня два вопроса.

Во-первых, я не уверен, каков эффект Rectangle.prototype.constructor = Rectangle. Даже когда я закомментировал эту строку, я все равно получил тот же результат. Чтобы помочь мне понять, я регистрирую "#### Inside Rectangle.constructor #####" внутри function Rectangle() {...}. Но это журналы, даже когда я закомментировал Rectangle.prototype.constructor = Rectangle.

Во-вторых, последние две строки, которые обе имеют rect.move(1, 2), ведут себя не так, как я ожидал. Первый вызов выводит 2, 4, а второй - 3, 6.

Мы начинаем с this.x = 1 и this.y = 2, определенных внутри родительского класса. В первый раз, когда мы вызываем rect.move(1,2), он добавляет для x: 1+1=2 и y: 2+2=4, как и ожидалось. Но во второй раз это не x: 2+2=4 и y: 4+4=8, как ожидалось. Вместо этого он сохраняет начальные значения this.x = 1 и this.y = 2 и выполняет x: 1+2=3 и y: 2+4=6.

Было бы здорово, если бы я мог исправить код, чтобы при первом вызове rect.move(1,2) выводит 2, 4 и выводит второй вызов 4, 8 и третий вывод 8, 16 и т. Д.

Спасибо.

Ответы [ 2 ]

2 голосов
/ 13 июля 2020

Что касается вашего первого вопроса, Rectangle.prototype.constructor = Rectangle не действует. Эта строка устанавливает конструктор класса Rectangle, но функция Rectangle() уже является конструктором, поэтому нет никакого эффекта.

Для вашего второго вопроса функция перемещения изменяет значение x объекта на x значение, переданное в функцию. То же самое и со значением y. 2 + 1 = 3 и 4 + 2 = 6

Если вы хотите, чтобы значения x и y удваивались каждый раз, вы можете использовать эту функцию:

Shape.prototype.move = function() {
    this.x += this.x; // <-- uses this.x instead of x parameter
    this.y += this.y; // <-- uses this.y instead of y parameter
    console.info('Shape moved.',this.x,this.y);
};
0 голосов
/ 13 июля 2020

Теперь я понимаю.

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function() {
  this.x += this.x;
  this.y += this.y;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(); // Outputs, 'Shape moved.'
rect.move(); // Outputs, 'Shape moved.'

Это выводит 1,2 -> 2,4 -> 4,8 -> ... и не требует аргументов для move ().

В исходном коде this.x и this.y сохраняются. Приносим извинения за путаницу и большое спасибо.

Вот рабочий код:

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function(a) {
  this.x = this.x + a;
  this.y = this.y + a;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(3); // x: 4, y: 5
rect.move(3); // x: 7, y: 8
rect.move(3); // x: 10, y: 11

Обратите внимание, что this.x и this.y являются постоянными.

...