Я пытаюсь изучить 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
Какую ошибку я здесь делаю?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я не могу дать вам объяснения прямо сейчас, потому что сначала мне нужно проверить свое предположение.
Но расширение возможно с использованием синтаксиса ES6:
function mapExtend(mapInstance) {
class MapExtend extends Map {}
return new MapExtend(mapInstance)
}
const b = new Map()
mapExtend(b).get(1)@batman Я думаю, это сработает, если вы можете вызвать конструктор Map в контексте экземпляра вашего объекта MapExtend (Map.apply(this, arguments). Я предполагаю, что он выполняет некоторые необходимые инициализации, но я не могу подтвердить это предположение прямо сейчас. Но вызов конструктор не работает, потому что тогда движок будет жаловаться, что конструктор должен быть вызван только с помощью new.
Для записи: medium.com/javascript-scene/…
Вы можете напрямую расширить прототип собственных объектов. Не все считают, что хорошая практика
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) };
}Расширение прототипа собственных объектов никогда не бывает хорошей идеей. Вы должны делать это только в том случае, если вы хотите полифилить функции, которые уже указаны, но не реализованы движком.
Вы также можете напрямую манипулировать прототипом map, например:
let collection = new Map ();
Map.prototype.customFunc = () => {console.info('customFunc')}
collection.customFunc();
Да, это выполнимо :) Но что удивительного, почему то же самое невозможно через функции .. :)