升级Google Maps JS API v3.58+后自定义Polyline类报错求助
问题描述
地图应用升级至Google Maps JavaScript API v3.58及以上版本后出现故障,自定义继承google.maps.Polyline的类无法正常实例化。
控制台报错
TypeError: Class constructors cannot be invoked without 'new' at new CustomPolyline.Polyline (webpack-internal:///...tomPolygon.js:31:32)
实例化代码
polylines.push(new CUST.CustomPolyline.Polyline(polygonType, this.mapInstance, polylineJSONObjects[i].coordinates, polylineJSONObjects[i].normalPolyAttributes, polylineJSONObjects[i].highlightPolyAttributes, polylineJSONObjects[i].normalPolyAttributes.mapLabelText));
自定义类核心代码
'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);
补充信息
- v3.57版本可正常运行,v3.58及以上版本触发错误
- 查阅官方发布说明未找到相关破坏性变更记录
- 疑问:是否为ECMAScript版本问题?如何在不重写数千行扩展类的前提下修复?
问题分析与修复方案
根本原因
Google Maps JavaScript API v3.58及以上版本中,google.maps.Polyline从原有的构造函数模式改为了ES6类模式。ES6类的构造函数必须通过new关键字调用,而原有代码通过apply/call直接调用父类构造函数、试图在自定义实例上执行父类逻辑的方式,违反了ES6类的调用规则,因此抛出错误。
修复方案(无需重写大量代码)
方案1:兼容ES5环境的实例继承改造
修改自定义类的构造逻辑,先创建原生Polyline实例,再挂载自定义原型与属性,保留原有命名空间和方法:
'use strict'; ( function (window, CUST, google) { if (typeof (CUST) === 'undefined') { CUST = {}; } // 提取原自定义方法到原型对象 const customPolylineMethods = { // 把原<... extension methods ...>中的方法移到此处 // 示例: toggleHighlight() { // ...原有高亮逻辑 }, updateLabel() { // ...原有标签更新逻辑 } }; CUST.CustomPolyline.Polyline = function(polyType, googleMap, dvgCoordinatesString, normalPolyAttributes, highlightPolyAttributes, labelText) { if (!(this instanceof CUST.CustomPolyline.Polyline)) { return new CUST.CustomPolyline.Polyline(...arguments); } // 转换为原生Polyline要求的options参数格式 const polylineOptions = { map: googleMap, path: dvgCoordinatesString, // 需确保是LatLng数组,必要时做格式转换 ...normalPolyAttributes }; // 创建原生Polyline实例 const polylineInstance = new google.maps.Polyline(polylineOptions); // 挂载自定义原型链,确保继承原生方法+自定义方法 Object.setPrototypeOf(customPolylineMethods, google.maps.Polyline.prototype); Object.setPrototypeOf(polylineInstance, customPolylineMethods); // 挂载自定义属性与原有初始化逻辑 polylineInstance.polyType = polyType; polylineInstance.highlightPolyAttributes = highlightPolyAttributes; polylineInstance.labelText = labelText; polylineInstance.base = google.maps.Polyline.prototype; // 执行原<... constructor initialization code ...>逻辑 // ...原有初始化代码 return polylineInstance; }; // 确保自定义类的原型指向正确,兼容原有实例判断逻辑 Object.assign(CUST.CustomPolyline.Polyline.prototype, customPolylineMethods); Object.setPrototypeOf(CUST.CustomPolyline.Polyline.prototype, google.maps.Polyline.prototype); })(window, window.CUST, window.google);
方案2:ES6类语法封装(环境支持ES6时优先)
用class extends语法封装原有逻辑,最小化代码改动:
'use strict'; ( function (window, CUST, google) { if (typeof (CUST) === 'undefined') { CUST = {}; } class CustomPolyline extends google.maps.Polyline { constructor(polyType, googleMap, dvgCoordinatesString, normalPolyAttributes, highlightPolyAttributes, labelText) { // 转换为原生Polyline要求的options参数 const polylineOptions = { map: googleMap, path: dvgCoordinatesString, ...normalPolyAttributes }; // 调用父类构造函数 super(polylineOptions); // 执行原有初始化逻辑 this.polyType = polyType; this.highlightPolyAttributes = highlightPolyAttributes; this.labelText = labelText; this.base = google.maps.Polyline.prototype; <... constructor initialization code ...> } // 直接迁移原<... extension methods ...>中的方法 toggleHighlight() { // ...原有高亮逻辑 } } CUST.CustomPolyline.Polyline = CustomPolyline; })(window, window.CUST, window.google);
关键注意事项
- 原生
google.maps.Polyline的构造函数仅接受一个options对象,原有代码传入的零散参数必须先转换为符合要求的格式,否则原生Polyline无法正常初始化。 - 两种方案均保留了原有命名空间
CUST.CustomPolyline.Polyline,因此实例化代码无需修改。
内容的提问来源于stack exchange,提问作者Terence Wight
相关产品推荐
相关产品推荐

