javascriptgoogle-maps-api-3

3.58 Breaking Change?


My mapping application broke with the upgrade to Google Maps JavaScript API v3.58 and above. I am trying to create a new google.maps.Polyline using a custom class that extends the Polyline with a few new methods I use frequently.

The error in the console is as follows:

TypeError: Class constructors cannot be invoked without 'new'
at new CustomPolyline.Polyline (webpack-internal:///...tomPolygon.js:31:32)

I create instances of my custom class using

  polylines.push(new CUST.CustomPolyline.Polyline(polygonType, this.mapInstance, polylineJSONObjects[i].coordinates, polylineJSONObjects[i].normalPolyAttributes, polylineJSONObjects[i].highlightPolyAttributes, polylineJSONObjects[i].normalPolyAttributes.mapLabelText));

The code executing is the constructor. I'm using a namespace called CUST and my extension is called CustomPolyline

'use strict';
(
  function (window, CUST, google) {

  if (typeof (CUST) === 'undefined') {
    CUST = {};
  }

  CUST.CustomPolyline.Polyline = function(polyType, googleMap, dvgCoordinatesString, 
                                       normalPolyAttributes, highlightPolyAttributes,
                                       labelText) {
  // Constructor
  if (this instanceof CustomPolyline.Polyline) {
    try {
      google.maps.Polyline.apply(this, arguments);
    } catch (ex) {
      // new Chrome update gave exception in 'apply' so used 'call'
      google.maps.Polyline.call(this, arguments);
    }

    this.base = google.maps.Polyline.prototype;

    <... constructor initialization code ...>
  }
 
  <... extension methods ...>

)(window, window.CUST, window.google);

If I switch to v3.57, this code works fine. I get the above error with any version newer than 3.57. I have reviewed all the release notes and see no indication of a breaking change in 3.58 that would cause this.

Could this be an ECMAScript version problem with the Google Maps API? If so, how can I fix it without rewriting my extension class completely (it's thousands of lines of code)?


Solution

  • Your code uses "function constructors" from the pre-ES6 world, and so did the Google Maps Javascript API until version 3.57. Search for

    _.to=function(a){ro.call(this,a)};
    

    in https://maps.googleapis.com/maps-api-v3/api/js/57/13/main.js, this is what eventually becomes google.maps.Polyline.

    But as of version 3.58 the Google Maps Javascript API uses ES6 classes, the code corresponding to google.maps.Polyline in https://maps.googleapis.com/maps-api-v3/api/js/58/11a/main.js is

    _.tq=class extends Ln{
    

    See here for a comparison of the syntax. Importantly, ES6 constructors cannot be invoked without the new keyword. Good question whether the switch to ES6 classes deserves to be called a breaking change and mentioned in the release notes.

    You can change your code so that CUST.CustomPolyline.Polyline is a subclass in the ES6 sense:

    CUST.CustomPolyline.Polyline = class extends google.maps.Polyline {
      constructor(polyType, googleMap, dvgCoordinatesString, 
                  normalPolyAttributes, highlightPolyAttributes,
                  labelText) {
        super(polyType, googleMap, dvgCoordinatesString, 
              normalPolyAttributes, highlightPolyAttributes,
              labelText);
        this.base = google.maps.Polyline.prototype;
        <... constructor initialization code ...>
      }
    };
    <... extension methods ...>
    

    This assumes that you define your extension methods like

    CUST.CustomPolyline.Polyline.prototype.method = function(...) {...}
    

    But it would be more in line with the new ES6 class syntax to define them inside the class { ... }.