Как правильно унаследовать массив через прототипы?
Конструктор 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 }
Дополнительно:
Так может массив вернуть из конструктора?
Array.apply(this, args);
чтобы инициализировать массив. Вопрос почему оно не работает
Если ты хочешь получить массив на выходе, возвращай массив, а если ты хочешь инстанс своего класса, то копируй все значения из массива и его длину в свой объект или мап. Только это будет не массив, это будет объект со структурой, как у массива.
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 };
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 тоже не работает) как-то по другому работают
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для правильного наследования массива через прототипы в JavaScript, можно воспользоваться следующим подходом:
1. Создайте конструктор для родительского объекта, который будет содержать массив:
```html
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); }
```
3. Создайте конструктор для дочернего объекта, который будет наследовать массив от родительского объекта:
```html
function ChildArray() { ParentArray.call(this); }
```
4. Установите прототип дочернего объекта равным экземпляру родительского объекта:
```html
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]
```
Таким образом, вы можете эффективно управлять наследованием массива через прототипы в JavaScript.