bogdan_uman
@bogdan_uman
шлЫмазл неукЪ-поцЪ

Наследование от Date?

Здравствуйте, подскажите пожалуйста.
Когда я создаю свой класс и наследую с новым синтаксисом, то все работает
class SpaceDate extends Date { }

let dateOriginal = new SpaceDate(2017, 1, 22);
console.log( dateOriginal.getDay() ); // 3
console.log( dateOriginal instanceof SpaceDate); // true


А вот если создаю через конструктор класса, то тогда ошибка

const SpaceDate = function( ...args ) {
    Date.call( this, ...args );
  }

  SpaceDate.prototype = Object.create( Date.prototype )
  SpaceDate.prototype.constructor = SpaceDate;

let dateOriginal = new SpaceDate(2017, 1, 22);
console.log( dateOriginal instanceof SpaceDate);
console.log( dateOriginal.getDay() );

Uncaught TypeError: this is not a Date object.


Class - это же семантический сахар над конструктором класса и прототипом, так почему же тогда через конструктор класса не получается создать? Спасибо.

Даже после транспилига Babel ошибка

spoiler
"use strict";

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

function _possibleConstructorReturn(self, call) {
  if (!self) {
    throw new ReferenceError(
      "this hasn't been initialised - super() hasn't been called"
    );
  }
  return call && (typeof call === "object" || typeof call === "function")
    ? call
    : self;
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError(
      "Super expression must either be null or a function, not " +
        typeof superClass
    );
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
  if (superClass)
    Object.setPrototypeOf
      ? Object.setPrototypeOf(subClass, superClass)
      : (subClass.__proto__ = superClass);
}

var SpaceDate = (function(_Date) {
  _inherits(SpaceDate, _Date);

  function SpaceDate() {
    _classCallCheck(this, SpaceDate);

    return _possibleConstructorReturn(
      this,
      (SpaceDate.__proto__ || Object.getPrototypeOf(SpaceDate))
        .apply(this, arguments)
    );
  }

  return SpaceDate;
})(Date);

var dateOriginal = new SpaceDate(2017, 1, 22);
console.log(dateOriginal instanceof SpaceDate);
console.log(dateOriginal.getDay());
  • Вопрос задан
  • 316 просмотров
Решения вопроса 1
rockon404
@rockon404
Frontend Developer
Проблема в том, что в методах прототипа Date идет проверка на то, что передан экземпляр даты. Причем проверка идет не по цепочке прототипов.
Старый исходный код V8:
function DateGetTime() {
  CHECK_DATE(this);
  return UTC_DATE_VALUE(this);
}

Кто-то писал, что CHECK_DATE имеет следующую реализацию:
CHECK_DATE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError());


Тем не менее, сейчас все это переписано на C++.

Если посмотреть спецификацию, то видно, что методы прототипа вызывают нативные функции, выполняющие все расчеты и тут важно, чтобы им предавали валидный объект даты. Поэтому, видимо, и идет строгая проверка.

Вариант решения этой проблемы, изменить цепочку прототипов экземпляра:
function SpaceDate(...args) {
  var date;
  date = new Date(...args);
  date.__proto__ = SpaceDate.prototype;
  return date;
}

SpaceDate.prototype.__proto__ = Date.prototype;

SpaceDate.prototype.test = function() {
  return this;
};

Возвращаться будет объект Date, а цепочка прототипов будет с вашими методами. На прототип оригинального объекта Date это никак не повлияет.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы