Search code examples
javascriptleafletecmascript-5

Javascript getter - why does it get called at construction?


I'm new to Javascript getters/setters, but thought to use them in my Leaflet- and browserify-based project. Got a surprise.

The getter gets called at initialization, for some reason unknown to me, before the class's own initialize method (Leaflet construction callback) gets to run. This of course means members are undefined and all breaks up. Why is this?

  • is this general behaviour with JavaScript getters?
  • is this induced by Leaflet (maybe a bug in it)?

Unfortunately, I haven't got a jsfiddle to showcase this - it may be due to Leaflet, or due to node.js like modular build (via browserify) that I do.

Here's the code:

/*
 * Temp.js
 */
"use strict";

module.exports = L.Class.extend( {

  initialize: function () {
    console.log("initialized");
  },

  // --- Public methods ---

  get some () {
    console.log("getter");
    return 42;
  },

  set some (v) {
    console.log("setter: "+v);
  }

});

Calling code:

// this just for experiments
//
var Temp = require('./src/Temp.js');
var xxx = new Temp();

Produces the output:

[Log] getter (out.js, line 2102)
[Log] initialized (out.js, line 2096)

So: what might call the get?

Using: Safari 8.0.6 (OS X), Leaflet current master, Browserify 10.1.0

Addendum:

Debugging, the line that calls the getter is this one in Leaflet.


Solution

  • I can't speak for Leaflet, but the usual implementation of extend has a loop that looks something like this:

    var propertyName;
    for (propertyName in source) {
        dest[propertyName] = source[propertyName];
    }
    

    As you can see, that reads the value of the property at the point you're calling extends (and stores the resulting value, instead of the getter function).

    You'll want to check the docs, but I doubt L.Class.extend is compatible with getters/setters. You may need to define those getters/setters in initialize instead, e.g.:

    var somePropDef = {
      get: function() {
        console.log("some getter");
        return 42;
      },
      set: function(v) {
        console.log("some setter: "+v);
      }
    };
    module.exports = L.Class.extend( {
    
      initialize: function () {
        Object.defineProperty(this, "some", somePropDef);
        console.log("initialized");
      },
    });