模块导出的闭包工厂无法访问导入方作用域问题如何解决?
结论
从其他模块导入的工厂函数返回的闭包,无法访问导入方所在的作用域。
底层原因
JavaScript采用词法作用域(静态作用域)规则,函数的作用域链在函数定义时就已经确定,和函数的调用位置、调用方式完全无关。
你给出的示例中,makeClosure和它返回的匿名函数定义在module.js中,它们的作用域链只能访问module.js内部的变量、以及JS全局作用域变量。两个ES模块的顶层作用域是完全隔离的,anotherModule.js中定义的someVar属于当前模块的私有作用域,module.js内的函数不可能直接访问到,所以运行代码会抛出someVar is not defined的错误。
适配你的业务需求的实现方案
你要封装通用的Google Maps API操作逻辑,只需要放弃依赖隐式作用域变量的思路,改成显式注入地图实例即可,推荐以下两种实现方式:
方案1:工厂函数绑定地图实例,返回专属操作集合
公共封装模块代码:
// googleMapUtils.js 公共模块 function createMapUtils(mapInstance) { // 所有返回的方法都闭包访问传入的地图实例,无需重复传参 return { // 添加标记点 addMarker(option) { return new google.maps.Marker({ ...option, map: mapInstance }) }, // 移动地图中心点 panTo(lat, lng) { mapInstance.panTo({ lat, lng }) }, // 其他需要复用的操作方法都可以在这里定义 } } export default createMapUtils
业务模块调用代码:
import createMapUtils from './googleMapUtils.js' // 当前业务页面初始化的独立地图实例 const myMap = new google.maps.Map(document.getElementById('map-container'), { zoom: 10, center: { lat: 39.9042, lng: 116.4074 } }) // 传入当前地图实例,得到只操作该实例的工具对象 const mapUtils = createMapUtils(myMap) // 直接调用方法即可,不用再传递地图实例 mapUtils.addMarker({ position: { lat: 39.9042, lng: 116.4074 }, title: '北京' })
方案2:纯工具函数,调用时显式传入地图实例
如果不需要预先绑定实例,追求更高的灵活性,也可以把所有操作方法写成第一个参数接收地图实例的形式:
// googleMapUtils.js 公共模块 export const addMarker = (mapInstance, option) => { return new google.maps.Marker({ ...option, map: mapInstance }) } export const panTo = (mapInstance, lat, lng) => { mapInstance.panTo({ lat, lng }) }
调用方式:
import { addMarker, panTo } from './googleMapUtils.js' const myMap = new google.maps.Map(/* 初始化参数 */) addMarker(myMap, { /* 标记点配置 */ }) panTo(myMap, 39.9042, 116.4074)
内容的提问来源于stack exchange,提问作者Ian Engelbrecht
相关产品推荐
相关产品推荐

