首页 > 解决方案 > 如何在避免权限错误的同时使用全局变量?

问题描述

请参见下面的示例,

function doSomething1(){/*needs ss*/const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);}
function doSomething2(){/*needs ss*/const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);}
function doItAll(){
  doSomething1();
  doSomething2();
}

而不是在这两个函数中调用电子表格,这可以使用全局变量简化为

const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);
function doSomething1(){/*do something with ss*/}
function doSomething2(){/*do something with ss*/}
function doItAll(){
  doSomething1();
  doSomething2();
}

这里的问题可以在不使用全局变量的情况下通过简单地ss在函数之间传递变量来解决。ss但是,对于需要访问变量的多个函数,这将变得更加复杂。而且传球ss很麻烦。没有很多方法可以避免 Apps 脚本中的全局变量。不支持模块。如果您使用 IIFE,则所有函数都对 IDE 隐藏 - 从 IDE 或其他任何地方调用函数是不可能的。在这里使用全局变量要优雅得多。但是如果我有一个简单的触发器,就会出现问题:

const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);
function doSomething1(){/*do something with ss*/}
function doSomething2(){/*do something with ss*/}
function doItAll(){
  doSomething1();
  doSomething2();
}
function onOpen(){/*Adds a menu*/}

菜单添加将失败,因为此行之前onOpen已加载,并且该行需要权限/授权,而作为简单触发器不会运行任何需要授权的代码。SpreadsheetApp.openById(/*SPREADSHEET_ID*/)onOpenonOpen

如何在不遇到授权错误的情况下声明全局变量?

标签: google-apps-scriptgoogle-sheetsglobal-variableslazy-loading

解决方案


这个问题可以通过使用getter来解决。getter 仅在从任何地方调用时才执行代码,从而将代码的执行封装在全局上下文中。但是 getter 将在每次调用变量时执行。如果ss在两个函数中调用,SpreadsheetApp.openById则执行两次。我们可以使用MDN 中提到的延迟加载技术来避免这种情况。

const config = {
  get ss() {
    delete this.ss;
    return (this.ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/));
  },
};
function doSomething1(){/*do something with config.ss*/}
function doSomething2(){/*do something with config.ss*/}
function doItAll(){
  doSomething1();
  doSomething2();
}
function onOpen(){/*Adds a menu*/}

在这里,我们在对象内部使用getter,而不是直接声明ss. 以这种方式使用,SpreadsheetApp.openById()永远不会在全局范围内调用,尽管它是在全局范围内声明的。它仅在doSomething1执行时加载。此外,从 访问该方法时不会再次调用该方法doSomething2,因为 getter 在第一次访问时被删除并替换为实际值。

虽然代码变得有点笨重,但这解决了很多问题并且更加优雅。

样品:


推荐阅读