2

You can change the behavior of a Leaflet.js class by including a mixin.

The tutorial Extending Leaflet: Class Theory says:

If a class is already defined, existing properties/methods can be redefined, or new ones can be added by using .include():

However when attempting to do this, I get a Maximum call stack size exceeded error.

var DemoClass = L.Class.extend({
  value: 42,
  demoMethod: function() {
    return this.value;
  }
});

DemoClass.include({
  demoMethod: function() {
    return DemoClass.prototype.demoMethod.call(this) * 2;
  },
  secondMethod: function() {
    return this.value;
  }
});

var instance = new DemoClass();
console.log("value=" + instance.value);
console.log("secondMethod()=" + instance.secondMethod());
console.log("demoMethod()=" + instance.demoMethod()); // gives a call stack exceeded
<script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>

If it's relevant, the actual code is overriding L.Marker.onAdd().

Gert
  • 532
  • 12
  • 19

2 Answers2

4
  demoMethod: function() {
    return DemoClass.prototype.demoMethod.call(this) * 2;
  },

You're making an infinite recursive call, right there.

JS is weird sometimes, and this time is one of those. By referring to DemoClass.prototype, you are referring to the latest state of DemoClass.prototype... so DemoClass.prototype.demoMethod is referring to itself.

Whenever you overwrite a prototype method or property, the previous one gets de-referenced and potentially garbage-collected.

If you want to refer to the previous definition of the method, you must keep a reference to the previous definition of the method.

This usually requires some trickery in the form of a JS closure (keeping a reference to the original value in some controlled variable scope). There are a variety of ways to do this: keep a reference to the previous prototype as a class property, like @Jaws does; do a closure somewhere; do a IIFE like in Leaflet.GridLayer.FadeOut, or anything that lets you keep a reference to the original method definition.

IvanSanchez
  • 18,272
  • 3
  • 30
  • 45
3

Try to isolate the base function:

var DemoClass = L.Class.extend({
  value: 42,
  demoMethod: function() {
    return this.value;
  }
});

DemoClass.include({
  baseDemoMethod: DemoClass.prototype.demoMethod,
  demoMethod: function() {
    return this.baseDemoMethod() * 2;
  },
  secondMethod: function() {
    return this.value;
  }
});

var instance = new DemoClass();
console.log("value=" + instance.value);
console.log("secondMethod()=" + instance.secondMethod());
console.log("demoMethod()=" + instance.demoMethod());
<script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
Jaws
  • 296
  • 1
  • 7