避免重复:是否在 Google Apps 脚本中使用全局变量?

Rol*_*olm 1 dry global-variables google-apps-script

截至 2021 年,对于 V8 引擎,我想知道在 Google Apps 脚本中使用全局变量是否是个好主意?如果是的话,如何使用它们?我的方法是个好方法吗(如下所述)?

\n

当然,现在我检查了所有其他类似的问题。但仍然有一些细节我找不到:
\n基本上我试图做的是不重复代码:我有多个函数,并且我正在存储活动电子表格和当前工作表,如下所示:

\n
const ss = SpreadsheetApp.getActiveSpreadsheet();\nconst sheet = ss.getActiveSheet();\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述\n这导致

\n
    \n
  1. 重复 (1)
  2. \n
  3. 浪费资源——实例化电子表格和工作表(2)
  4. \n
  5. 增加变量名称不一致(ss /电子表格/电子表格 - 从网络上的片段复制/粘贴时)(3)
  6. \n
\n

正确的?

\n

因此,每当我在多个函数中有公共局部变量时,我就想到使用全局变量(GV)。

\n

然而,由于它们\xe2\x80\x99re将在每个函数调用上不必要地分配(还有其他不需要GV的函数),所以我尝试仅在需要时定义它们(仅当有函数时)使用它们的调用) - 不使用定义关键字(var、const、let):\n在此输入图像描述

\n

根据这个链接,这似乎是一个很好的方法(模式1)。

\n

无论如何,我想知道是否还有其他我不知道的考虑因素或缺点?走这条路真的是个好主意吗?因为到目前为止,我没有看到\xe2\x80\x99有任何实现这个的代码片段,而且我看到了很多GAS代码片段。

\n

我知道的一个缺点是我的 GV 在新的 GAS 编辑器中缺乏自动补全功能(因为我没有使用“var”或“let”来定义它们来故意将其范围设置为 Global )。

\n

否则,我知道 PropertiesService 和 CacheService。不过,我愿意重用我的脚本(我在其中定义了 GV)作为其他脚本的库。
\n另外,您只能将值作为字符串存储在 PropertiesService 和 CacheService 中(而不是 SpreadsheetApp.getActiveSpreadsheet() 中),对吗?更不用说脚本执行后我不需要持久性。
\n所以我也犹豫是否使用它们而不是 GV。

\n

The*_*ter 6

  • 您可以在我的回答中使用延迟加载技术
  • 为了使其动态并避免重复,您可以使用封闭的箭头函数(()=>{})来避免直接执行并使用Object.defineProperty()添加getter。
  • 这种方法的显着优点之一是模块化延迟加载。如果不需要某个对象,则不会加载该对象。如果您有sssheet1sheet2rangeOfSheet1rangeOfSheet2作为全局变量,如果您访问rangeOfSheet1,则仅加载它的依赖项,即sheet1ss。其余的都没有动过。
const g = {};//global object
const addGetter_ = (name, value, obj = g) => {
  Object.defineProperty(obj, name, {
    enumerable: true,
    configurable: true,
    get() {
      delete this[name];
      return (this[name] = value());
    },
  });
  return obj;
};

//MY GLOBAL VARIABLES in g
[
  ['ss', () => SpreadsheetApp.getActive()],
  ['MasterSheet', () => g.ss.getSheetByName('Sheet1')],
  ['MasterRangeColA1_5', () => g.MasterSheet.getRange('A1:A5')],
  ['MasterRangeColAValues', () => g.MasterRangeColA1_5.getValues()],
].forEach(([n, v]) => addGetter_(n, v));

const test = () => {
  console.info('start');
  console.log({ g });
  console.info('Accessing MasterSheet');
  console.log(g.MasterSheet);
  console.log({ g }); //note ss is loaded as well
  console.info('Accessing MasterRangeColAValues');
  console.log(g.MasterRangeColAValues);
  console.log({ g }); //note MasterRangeColA1_5 is loaded as well
};
Run Code Online (Sandbox Code Playgroud)

除了全局对象之外g,我们还可以使用 global this,在这种情况下,所有变量都直接成为全局对象的成员:

const addGetter_ = (name, value, obj = this) => {
  Object.defineProperty(obj, name, {
    enumerable: true,
    configurable: true,
    get() {
      delete this[name];
      return (this[name] = value());
    },
  });
  return obj;
};
[
  ['ss', () => SpreadsheetApp.getActive()],
  ['MasterSheet', () => ss.getSheetByName('Sheet1')],
  ['MasterRangeColA1_5', () => MasterSheet.getRange('A1:A5')],
  ['MasterRangeColAValues', () => MasterRangeColA1_5.getValues()],
].forEach(([n, v]) => addGetter_(n, v));

const test = () => {
  console.info('start');
  console.log(this);
  console.info('Accessing MasterSheet');
  console.log(MasterSheet);
  console.log(this); //note ss is loaded as well
  console.info('Accessing MasterRangeColAValues');
  console.log(MasterRangeColAValues);
  console.log(this); //note MasterRangeColA1_5 is loaded as well
};
Run Code Online (Sandbox Code Playgroud)
  • 优点:不必在变量前加上g.But,全局空间被污染。

  • 哇哦,又学到新东西了。现在明白了,但我以前从未见过这样的编码方式,它非常强大。您定义一个函数,使其在第一次执行时的行为与下一次执行时的行为不同......嗯......让我想起了递归函数(我所知道的与此最接近的语法)。不管怎样,现在一切都好了。再次感谢你。真的很感激。 (2认同)