Как правильно унаследовать массив через прототипы?

Ссылка скопирована
1 ответ

Конструктор Array не срабатывает так как ожидалось:

'use strict';  const RevercedArray = function(...args) {   Array.apply(this, args); };  Object.setPrototypeOf(RevercedArray.prototype, Array.prototype);  const arr = new RevercedArray(1, 2, 3);  console.log(arr); // RevercedArray {}

'use strict'; const RevercedArray = function(...args) { Array.apply(this, args); }; Object.setPrototypeOf(RevercedArray.prototype, Array.prototype); const arr = new RevercedArray(1, 2, 3); console.log(arr); // RevercedArray {}

UPD
Я хочу сделать что-то похожее на это:

const Rectangle = function(x, y, width, height) {   this.x = x;   this.y = y;   this.width = width;   this.height = height; };  Rectangle.prototype.area = function() {   return this.width * this.height; };  const Square = function(x, y, length) {   Rectangle.call(this, x, y, length, length); };  Object.setPrototypeOf(Square.prototype, Rectangle.prototype);  const sq = new Square(1, 2, 3); console.log(sq); // Square { x: 1, y: 2, width: 3, height: 3 }

const Rectangle = function(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; }; Rectangle.prototype.area = function() { return this.width * this.height; }; const Square = function(x, y, length) { Rectangle.call(this, x, y, length, length); }; Object.setPrototypeOf(Square.prototype, Rectangle.prototype); const sq = new Square(1, 2, 3); console.log(sq); // Square { x: 1, y: 2, width: 3, height: 3 }

Дополнительно:

Так может массив вернуть из конструктора?

  • WbICHA, я специально вызываю
    Array.apply(this, args);
    чтобы инициализировать массив. Вопрос почему оно не работает
  • serhiops, молодец, и? Дальше что? С тем же успехом ты мог там написать const a = 1 и потом спрашивать "где а?".
    Если ты хочешь получить массив на выходе, возвращай массив, а если ты хочешь инстанс своего класса, то копируй все значения из массива и его длину в свой объект или мап. Только это будет не массив, это будет объект со структурой, как у массива.
    const RevercedArray = function(...args) {     const arr = Array.apply(this, args);     arr.forEach((v, i) => {       this[i] = v     })     this.length = arr.length   };

    const RevercedArray = function(...args) { const arr = Array.apply(this, args); arr.forEach((v, i) => { this[i] = v }) this.length = arr.length };

  • WbICHA, зачем мне делать псевдомассив вручную? Я вызываю конструктор класса, связывая с ним this, чтобы он сам инициализировал текущий объект. Вопрос в том, почему конструктор не заполняет this значениями. В твоём примере кода вообще не нужно создавать массив arr, это просто копия того, который через аргументы приходит
  • serhiops, всё, проблема ясна и решение очевидно. Забудь о той фигне, что я выше написал, вот решение:

    spoiler

    function _defineProperties(target, props) {   for (let i = 0; i < props.length; i++) {     const descriptor = props[i];     descriptor.enumerable = descriptor.enumerable || false;     descriptor.configurable = true;     if ('value' in descriptor) {       descriptor.writable = true;     }     Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);   } } function _createClass(Constructor, protoProps, staticProps) {   if (protoProps) {     _defineProperties(Constructor.prototype, protoProps);   }   if (staticProps) {     _defineProperties(Constructor, staticProps);   }   Object.defineProperty(Constructor, 'prototype', { writable: false });   return Constructor; } function _toPropertyKey(t) {   const i = _toPrimitive(t, 'string');   return typeof i === 'symbol' ? i : String(i); } function _toPrimitive(t, r) {   if (typeof t !== 'object' || !t) {     return t;   }   const e = t[Symbol.toPrimitive];   if (void 0 !== e) {     const i = e.call(t, r || 'default');     if (typeof i !== 'object') {       return i;     }     throw new TypeError('@@toPrimitive must return a primitive value.');   }   return (r === 'string' ? String : Number)(t); } function _classCallCheck(instance, Constructor) {   if (!(instance instanceof Constructor)) {     throw new TypeError('Cannot call a class as a function');   } } function _callSuper(t, o, e) {   return (     (o = _getPrototypeOf(o)),     _possibleConstructorReturn(       t,       _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e),     )   ); } function _possibleConstructorReturn(self, call) {   if (call && (typeof call === 'object' || typeof call === 'function')) {     return call;   } else if (call !== void 0) {     throw new TypeError('Derived constructors may only return object or undefined');   }   return _assertThisInitialized(self); } function _assertThisInitialized(self) {   if (self === void 0) {     throw new ReferenceError("this hasn't been initialised - super() hasn't been called");   }   return self; } function _inherits(subClass, superClass) {   if (typeof superClass !== 'function' && superClass !== null) {     throw new TypeError('Super expression must either be null or a function');   }   subClass.prototype = Object.create(superClass && superClass.prototype, {     constructor: { value: subClass, writable: true, configurable: true },   });   Object.defineProperty(subClass, 'prototype', { writable: false });   if (superClass) {     _setPrototypeOf(subClass, superClass);   } } function _wrapNativeSuper(Class) {   const _cache = typeof Map === 'function' ? new Map() : undefined;   _wrapNativeSuper = function _wrapNativeSuper(Class) {     if (Class === null || !_isNativeFunction(Class)) {       return Class;     }     if (typeof Class !== 'function') {       throw new TypeError('Super expression must either be null or a function');     }     if (typeof _cache !== 'undefined') {       if (_cache.has(Class)) {         return _cache.get(Class);       }       _cache.set(Class, Wrapper);     }     function Wrapper() {       return _construct(Class, arguments, _getPrototypeOf(this).constructor);     }     Wrapper.prototype = Object.create(Class.prototype, {       constructor: {         value: Wrapper,         enumerable: false,         writable: true,         configurable: true,       },     });     return _setPrototypeOf(Wrapper, Class);   };   return _wrapNativeSuper(Class); } function _construct(t, e, r) {   if (_isNativeReflectConstruct()) {     return Reflect.construct.apply(null, arguments);   }   const o = [null];   o.push.apply(o, e);   const p = new (t.bind.apply(t, o))();   return r && _setPrototypeOf(p, r.prototype), p; } function _isNativeReflectConstruct() {   try {     var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], () => {}));   } catch (err) {}   return (_isNativeReflectConstruct = function _isNativeReflectConstruct() {     return !!t;   })(); } function _isNativeFunction(fn) {   try {     return Function.toString.call(fn).indexOf('[native code]') !== -1;   } catch (err) {     return typeof fn === 'function';   } } function _setPrototypeOf(o, p) {   _setPrototypeOf = Object.setPrototypeOf     ? Object.setPrototypeOf.bind()     : function _setPrototypeOf(o, p) {         o.__proto__ = p;         return o;       };   return _setPrototypeOf(o, p); } function _getPrototypeOf(o) {   _getPrototypeOf = Object.setPrototypeOf     ? Object.getPrototypeOf.bind()     : function _getPrototypeOf(o) {         return o.__proto__ || Object.getPrototypeOf(o);       };   return _getPrototypeOf(o); } const ReversedArray = /* #__PURE__*/ (function (_Array) {   _inherits(ReversedArray, _Array);   function ReversedArray() {     _classCallCheck(this, ReversedArray);     return _callSuper(this, ReversedArray, arguments);   }   return _createClass(ReversedArray); })(/* #__PURE__*/ _wrapNativeSuper(Array));  const arr = new ReversedArray(1, 2, 3);  console.log(arr);

    function _defineProperties(target, props) { for (let i = 0; i < props.length; i++) { const descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) { descriptor.writable = true; } Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) { _defineProperties(Constructor.prototype, protoProps); } if (staticProps) { _defineProperties(Constructor, staticProps); } Object.defineProperty(Constructor, 'prototype', { writable: false }); return Constructor; } function _toPropertyKey(t) { const i = _toPrimitive(t, 'string'); return typeof i === 'symbol' ? i : String(i); } function _toPrimitive(t, r) { if (typeof t !== 'object' || !t) { return t; } const e = t[Symbol.toPrimitive]; if (void 0 !== e) { const i = e.call(t, r || 'default'); if (typeof i !== 'object') { return i; } throw new TypeError('@@toPrimitive must return a primitive value.'); } return (r === 'string' ? String : Number)(t); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _callSuper(t, o, e) { return ( (o = _getPrototypeOf(o)), _possibleConstructorReturn( t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e), ) ); } function _possibleConstructorReturn(self, call) { if (call && (typeof call === 'object' || typeof call === 'function')) { return call; } else if (call !== void 0) { throw new TypeError('Derived constructors may only return object or undefined'); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function'); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true }, }); Object.defineProperty(subClass, 'prototype', { writable: false }); if (superClass) { _setPrototypeOf(subClass, superClass); } } function _wrapNativeSuper(Class) { const _cache = typeof Map === 'function' ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) { return Class; } if (typeof Class !== 'function') { throw new TypeError('Super expression must either be null or a function'); } if (typeof _cache !== 'undefined') { if (_cache.has(Class)) { return _cache.get(Class); } _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true, }, }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } function _construct(t, e, r) { if (_isNativeReflectConstruct()) { return Reflect.construct.apply(null, arguments); } const o = [null]; o.push.apply(o, e); const p = new (t.bind.apply(t, o))(); return r && _setPrototypeOf(p, r.prototype), p; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], () => {})); } catch (err) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _isNativeFunction(fn) { try { return Function.toString.call(fn).indexOf('[native code]') !== -1; } catch (err) { return typeof fn === 'function'; } } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } const ReversedArray = /* #__PURE__*/ (function (_Array) { _inherits(ReversedArray, _Array); function ReversedArray() { _classCallCheck(this, ReversedArray); return _callSuper(this, ReversedArray, arguments); } return _createClass(ReversedArray); })(/* #__PURE__*/ _wrapNativeSuper(Array)); const arr = new ReversedArray(1, 2, 3); console.log(arr);

    Спасибо бабелю за проделанную работу. Так выглядит полифил для 3ёх строчек кода:

    class ReversedArray extends Array {}  const arr = new ReversedArray(1, 2, 3)  console.log(arr);

    class ReversedArray extends Array {} const arr = new ReversedArray(1, 2, 3) console.log(arr);

  • Проблема решена. Ссылка на документацию: https://developer.mozilla.org/en-US/docs/Web/JavaS...
    Рабочий код:

    'use strict';  const RevercedArray = function(...args) {   return Reflect.construct(Array, args, new.target); };  Object.setPrototypeOf(RevercedArray.prototype, Array.prototype);  const arr = new RevercedArray(1, 2, 3);  console.log(arr); // RevercedArray(3) [ 1, 2, 3 ]

    'use strict'; const RevercedArray = function(...args) { return Reflect.construct(Array, args, new.target); }; Object.setPrototypeOf(RevercedArray.prototype, Array.prototype); const arr = new RevercedArray(1, 2, 3); console.log(arr); // RevercedArray(3) [ 1, 2, 3 ]

    Ответы:

    https://learn.javascript.ru/extend-natives

    • да оно понятно, что можно через классы наследовать, я хотел узнать как это сделать через прототипы
    • serhiops, а зачем? Тебе эти знания пригодятся примерно никогда.
    • WbICHA, скорее в академических целях. Для полной картины как все устроено
    • WbICHA, Обновил вопрос, возможно теперь станет понятнее. Пока что у меня только догадки, что встроенные функции-конструкторы(с Map тоже не работает) как-то по другому работают
    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Ольга Сеть Ответ

    Для правильного наследования массива через прототипы в JavaScript, можно воспользоваться следующим подходом:

    1. Создайте конструктор для родительского объекта, который будет содержать массив:

    ```html

    function ParentArray() {
      this.array = [1, 2, 3, 4, 5];
    }

    function ParentArray() { this.array = [1, 2, 3, 4, 5]; }

    ```

    2. Добавьте методы в прототип родительского объекта для работы с массивом:

    ```html

    ParentArray.prototype.getArray = function() {
      return this.array;
    }
     
    ParentArray.prototype.addToEnd = function(item) {
      this.array.push(item);
    }

    ParentArray.prototype.getArray = function() { return this.array; } ParentArray.prototype.addToEnd = function(item) { this.array.push(item); }

    ```

    3. Создайте конструктор для дочернего объекта, который будет наследовать массив от родительского объекта:

    ```html

    function ChildArray() {
      ParentArray.call(this);
    }

    function ChildArray() { ParentArray.call(this); }

    ```

    4. Установите прототип дочернего объекта равным экземпляру родительского объекта:

    ```html

    ChildArray.prototype = Object.create(ParentArray.prototype);
    ChildArray.prototype.constructor = ChildArray;

    ChildArray.prototype = Object.create(ParentArray.prototype); ChildArray.prototype.constructor = ChildArray;

    ```

    Теперь у вас есть правильное наследование массива через прототипы в JavaScript. Вы можете создать экземпляр дочернего объекта и использовать методы родительского объекта для работы с массивом:

    ```html

    var child = new ChildArray();
    console.log(child.getArray()); // [1, 2, 3, 4, 5]
    child.addToEnd(6);
    console.log(child.getArray()); // [1, 2, 3, 4, 5, 6]

    var child = new ChildArray(); console.log(child.getArray()); // [1, 2, 3, 4, 5] child.addToEnd(6); console.log(child.getArray()); // [1, 2, 3, 4, 5, 6]

    ```

    Таким образом, вы можете эффективно управлять наследованием массива через прототипы в JavaScript.

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно