Как расширить карту в js?

Я пытаюсь изучить js и пытаюсь расширить Map. Я сделал:

function mapExtend(mapInstance) {
  function MapExtend(){
  }

  MapExtend.prototype = Object.create(Map.prototype);
  MapExtend.prototype.constructor = MapExtend;

  return new MapExtend(mapInstance)
}

И я сделал это:

const b = new Map()
mapExtend(b).get(1)

Я получаю следующую ошибку:

Uncaught TypeError: Method Map.prototype.get called on incompatible receiver #<MapExtend>
    at MapExtend.get (<anonymous>)
    at <anonymous>:1:14

Какую ошибку я здесь делаю?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
0
695
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я не могу дать вам объяснения прямо сейчас, потому что сначала мне нужно проверить свое предположение.

Но расширение возможно с использованием синтаксиса ES6:

function mapExtend(mapInstance) {
  class MapExtend extends Map {}

  return new MapExtend(mapInstance)
}

const b = new Map()
mapExtend(b).get(1)

Да, это выполнимо :) Но что удивительного, почему то же самое невозможно через функции .. :)

batman 25.08.2018 10:29

@batman Я думаю, это сработает, если вы можете вызвать конструктор Map в контексте экземпляра вашего объекта MapExtend (Map.apply(this, arguments). Я предполагаю, что он выполняет некоторые необходимые инициализации, но я не могу подтвердить это предположение прямо сейчас. Но вызов конструктор не работает, потому что тогда движок будет жаловаться, что конструктор должен быть вызван только с помощью new.

t.niese 25.08.2018 10:31

Для записи: medium.com/javascript-scene/…

KooiInc 25.08.2018 13:34

Вы можете напрямую расширить прототип собственных объектов. Не все считают, что хорошая практика

Map.prototype.reportSize = function () {
    return `This map contains ${this.size} ${this.size === 1 ? "entry" : "entries"}`;
};

var x = new Map();
console.info(x.reportSize());
x.set(3, "three");
console.info(x.reportSize());

В качестве альтернативы вы можете создать собственную функцию, используя внутри нее расширения. Таким образом, вам не нужно расширять prototype из Map

const MapWithExtensions = map => {
  return {
    map: map,
    reportSize: function () {
     return `This map contains ${this.map.size} ${
      this.map.size === 1 ? "entry" : "entries"}`; 
    }
  };
};
const myMap = MapWithExtensions(new Map);
console.info(myMap.reportSize());
myMap.map.set(9, "nine");
console.info(myMap.reportSize());
console.info(myMap.map.get(9));

Наконец, это может быть способ создать расширенный Map без расширения прототипа Map (фактически, он сопоставляет ключи Map.prototype с методами в расширенном Map).

const xMap = MapFactory({
  mySize: function() {return `Hi. My size is currently ${this.size}`}
});
const myMap = xMap.Create();
console.info(myMap.mySize());
console.info("setting [5, \"five\"]")
myMap.set(5, "five");
console.info(myMap.mySize());
console.info(myMap.entries().next().value);

function MapFactory(extensions = {}) {
  const proto = new Map;
  const mappings = Object.getOwnPropertyNames(Map.prototype)
    .reduce( (reduced, key) => { 
      if (proto[key].constructor !== Function) {
        reduced.localProps.push(key);
      } else {
        reduced.proto[key] = function (...args) { return this.map[key](...args); };
      }
      return reduced;
    },
    { localProps: [], proto: {} }
  );
  const XMap = function (map) {
      this.map = map;
      mappings.localProps.forEach( prop =>
        Object.defineProperty(this, prop, { get() {return this.map[prop]; }}) 
      );
  };
  XMap.prototype = {...mappings.proto, ...extensions};
  return { Create: (map = new Map) => new XMap(map) };
}

Расширение прототипа собственных объектов никогда не бывает хорошей идеей. Вы должны делать это только в том случае, если вы хотите полифилить функции, которые уже указаны, но не реализованы движком.

t.niese 25.08.2018 10:29

Вы также можете напрямую манипулировать прототипом map, например:

let collection =  new Map ();

Map.prototype.customFunc = () => {console.info('customFunc')}

collection.customFunc();

Другие вопросы по теме