Javascript 使用ES6模块重新导出全局变量

Javascript 使用ES6模块重新导出全局变量,javascript,ecmascript-6,Javascript,Ecmascript 6,我正在将JS脚本迁移到ES6模块。客户端代码的一种常见模式是将跟踪信息推送到窗口对象上的全局数组。一个具体的例子是window.dataLayerarray 我想将这些全局数据抽象到ES6模块中,而不是指示linter使用/*全局数据层*/忽略它们,因为这使代码更容易理解。我的第一次尝试是创建如下垫片: export default window.dataLayer; 但是,如“实施视图”部分所述,上述代码相当于: const *default* = window.dataLayer; //

我正在将JS脚本迁移到ES6模块。客户端代码的一种常见模式是将跟踪信息推送到
窗口
对象上的全局数组。一个具体的例子是
window.dataLayer
array

我想将这些全局数据抽象到ES6模块中,而不是指示linter使用
/*全局数据层*/
忽略它们,因为这使代码更容易理解。我的第一次尝试是创建如下垫片:

export default window.dataLayer;
但是,如“实施视图”部分所述,上述代码相当于:

const *default* = window.dataLayer; // *not* legal JavaScript
export { *default* as default };
因此,每个模块内的
窗口。dataLayer
数组将是原始
窗口的副本。dataLater
数组:当GTM异步引导时,从模块推送的事件不会被它看到,因为只有本地
*默认值*
才会有这些事件


使用ES6模块处理此类全局性问题的推荐方法是什么,它不涉及像使用代理这样的重量级解决方案?在一个模块化系统中有很多全局变量确实让人感觉很糟糕。

与您在问题中描述的相反,正确的处理方法是:

/* data-layer.js */
window.dataLayer = [];
export default window.dataLayer;
…以及任何需要推进到“数据层”阵列的模块,只需要以下内容:

import dataLayer from 'data-layer';

// ... some code I assume

dataLayer.push({
  'pageCategory': 'signup',
  'visitorType': 'high-value'
});
/* gtm-container.js */
import 'this';
import 'that';
import otherThing from 'the-other-thing'; // lets assume it returns a promise
import dataLayer from 'data-layer'l

otherThing.then(value => {
   invokeSnippet()
})
.catch(err => {
   handleError(err);
});

function invokeSnippet() {
(function(w,d,s,i){dataLayer.push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX')
}
由于ES6导入将只读引用传递给导出,因此它不是要导入的阵列的副本,而是在data-layer.js中创建和导出的阵列

但棘手的部分是,您必须修改Google Tag Manager容器片段,使其不会在加载后立即运行,而是仅在所有可能修改数据层的脚本运行后运行

如果要将GTM容器代码段作为一个模块单独加载,则在调用代码段之前,可能需要先导入所有可能修改数据的脚本(并确保该部分实际运行)

比如:

import dataLayer from 'data-layer';

// ... some code I assume

dataLayer.push({
  'pageCategory': 'signup',
  'visitorType': 'high-value'
});
/* gtm-container.js */
import 'this';
import 'that';
import otherThing from 'the-other-thing'; // lets assume it returns a promise
import dataLayer from 'data-layer'l

otherThing.then(value => {
   invokeSnippet()
})
.catch(err => {
   handleError(err);
});

function invokeSnippet() {
(function(w,d,s,i){dataLayer.push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX')
}
但是,你知道,这并不是对如何做到这一点的真正解释,只是一个想法,我不知道可能会给数据层添加什么不同的东西,因为你正在转向一个异步模块模式,你必须理解异步运行所有这些脚本将如何改变你使用GTM系统的方式,它被清楚地写为使用globals同步运行

我想知道谷歌是否会很快用现代JavaScript更新这些东西,或者是否有更模块化的选项可用

如果你不知道,我应该提一下: 许多(大多数)ES6/ES2015功能,包括模块,到今天(2016年1月)还不能在浏览器中使用,因此您需要某种构建或加载程序来在浏览器中运行这些功能(如webpack、browserify、stealjs、jspm或带有babel或tracuer的东西)


可能是最容易开始的。

您的示例中没有任何内容是数组的副本,因此我不确定您真正的要求是什么。每个模块中的“因此,
窗口。数据层
数组将是原始
窗口的副本。dataLater
数组”这句话没有任何意义。