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());
  • Вопрос задан
  • 291 просмотр
Решения вопроса 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 это никак не повлияет.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
25 апр. 2024, в 12:20
15000 руб./за проект
25 апр. 2024, в 12:08
300 руб./за проект
25 апр. 2024, в 11:49
25000 руб./за проект