В классе-наследнике методы не выводят нужные значения

Изучаю наследование и делаю такой примерчик:

//Класс "геометрическая фигура", от которого должны наследоваться 
//все остальные классы геометрических фигур
function GeometricFigure(){
  let S=0;//площадь
  let P=0;//периметр
  this.getS=function(){
    return S;
  };
  this.getP=function(){
    return P;
  };
}

/*Класс "четырехугольник", который наследуется от класса"геометрическая фигура
и станет родителем для остальных фигур четырехугольников
*/
function Quadrangle(){
  GeometricFigure.call(this);
}
Quadrangle.prototype=Object.create(GeometricFigure.prototype);

/*От него наследуется класс "квадрат" */
function Square(side){
  Quadrangle.call(this);
  this.side=side;
  let S=side*side;
  let P=side*4;
}
Square.prototype=Object.create(Quadrangle.prototype);
 
let square=new Square(12);

console.log(square.getS());
console.log(square.getP());

Почему выводиться 0, а не значения, которые должны содержаться переменных S и P?


Ответы (2 шт):

Автор решения: vsemozhetbyt

Переменные, создаваемые при помощи let, остаются локальными переменными внутри функции или блока. Поэтому переменные внутри Square недоступны для методов, которые вы определили внутри GeometricFigure. В Square вы не переопределили эти переменные, а создали новые, которые никак не используются. Вам нужно добавить в GeometricFigure способы перезаписи этих переменных, что-то вроде setS() и setP().

→ Ссылка
Автор решения: OPTIMUS PRIME

Потому что здесь:

function GeometricFigure(){
  let S=0;//площадь
  let P=0;//периметр
  this.getS=function(){
    return S;
  };
  this.getP=function(){
    return P;
  };
}

Создается замыкание. return S возвращает вон тот let S = 0; а должен находиться в прототипе, и возвращать this.S (который в свою очередь должен добавляться в объект, вместо let S):

function _inheritsLoose(subClass, superClass) {
  subClass.prototype = Object.create(superClass.prototype);
  subClass.prototype.constructor = subClass;
  subClass.__proto__ = superClass;
}

/***/
function GeometricFigure() {
  this.S = 0;
  this.P = 0;
}

GeometricFigure.prototype.getS = function() {
  return this.S;
};
GeometricFigure.prototype.getP = function() {
  return this.P;
};

/***/
_inheritsLoose(Quadrangle, GeometricFigure);

function Quadrangle() {
  GeometricFigure.call(this);
}

/***/
_inheritsLoose(Square, Quadrangle);

function Square(side) {
  Quadrangle.call(this);

  this.side = side;
  this.S = side * side;
  this.P = side * 4;
}

/***/

let square = new Square(12);

console.log(square.getS());
console.log(square.getP());

Чтобы не писать такую путаницу, ввели сахарные классы:

class GeometricFigure {
  constructor() {
    this.S = 0;
    this.P = 0;
  }
  
  /***/
  getS() {
    return this.S;
  }
  getP() {
    return this.P;
  }
}

class Quadrangle extends GeometricFigure {}

class Square extends Quadrangle {
  constructor(side) {
    super();
    this.side = side;
    this.S = side * side;
    this.P = side * 4;
  }
}

/***/

let square = new Square(12);

console.log(square.getS());
console.log(square.getP());

Можно скопировать код туда → https://babeljs.io/repl и посмотреть, что будет)

→ Ссылка