全局保存数组

Saving an array globally

我想要达到的目标

我有一个包含 2 张纸的电子表格 A & B

NameSheet B 引用 NameSheet A 的数据。 Whenever a name is selected, I want to populate Amount column in B with Amount in column of sheet A as a placeholder which users can override.为此,我计划将 Sheet A 数据加载到一个数组(全局可用)中,以便在 onEdit(e) 中我可以引用该数组而不是访问 Sheet B.

但我能找到的选项 - CacheServicePropertyService - 仅保存字符串值。但我想要:

var myGlobalArray = [];

function on init(){
    //iterate and fill the array such that it has following output
    //myGlobalArray[Name1] = 1
    //myGlobalArray[Name2] = 2
    //myGlobalArray[Name3] = 3
}

function onEdit(e){ 
  //if selected value is name1, populate myGolbalArray[Name1] value in Amount
}

问题 在哪里以及如何定义 myGlobalArray?

我尝试将缓存服务与 JSON.StringifyJSON.parse 一起使用,但数组在 onEdit 中为空。

CacheService 和 PropertyService 确实只保存字符串值,但您可以使用 JSON utilities JSON.stringify() and JSON.parse().

存储任何标量数据
// Save an array in cache service
CacheService.getPublicCache()
            .put("myGlobalArray", JSON.stringify(myGlobalArray));

// Retrieve an array from property service
var myGlobalArray = JSON.parse( CacheService.getPublicCache()
                                                 .get("myGlobalArray") );

// Save an array in property service
PropertiesService.getDocumentProperties()
                 .setProperty("myGlobalArray", JSON.stringify(myGlobalArray));

// Retrieve an array from property service
var myGlobalArray = JSON.parse( PropertiesService.getDocumentProperties()
                                                 .getProperty("myGlobalArray") );

当调用变量 "Global" 时,我们指的是它的 范围 ,表示它可用于同一模块中的所有代码。 (您可以在 What is the scope of variables in JavaScript? 中阅读有关范围的更多信息)

但是由于您正在查看 CacheService 和 PropertyService,您已经知道范围只是问题的一部分。每次调用 onEdit() 时,它将在 Google 的其中一台服务器上的新执行实例中 运行。此新实例将无法使用先前实例中全局变量中的值。因此,我们需要在每次新调用脚本时填充 "global variable"。

引用全局变量的一种优雅方法是作为特殊 this 对象的名称属性。比如我们脚本中的每个函数都可以引用this.myGlobalArray.1

例如,您可以将 Class Cache 文档中的 getRssFeed() 示例改编成 get_myGlobalArray()。然后你的 onEdit() 触发器只需要首先调用它来确保 this.myGlobalArray 包含相关的数组数据。

function onEdit(e){ 
  get_myGlobalArray();

  //if selected value is name1, populate myGlobalArray[Name1] value in Amount
  ...
  sheet.getRange(e.range.getRow(),2).setValue(myGlobalArray[e.value]);
}

/**
 * Ensure the global variable "myGlobalArray" is defined and contains the
 * values of column A in SheetA as an array.
 */
function get_myGlobalArray() {
  if (typeof this.myGlobalArray == 'undefined') {
    // Global variable doesn't exist, so need to populate it
    // First, check for cached value
    var cache = CacheService.getPublicCache();
    var cached = cache.get("myGlobalArray");
    if (cached) {
      // We have a cached value, so parse it and store in global
      this.myGlobalArray = JSON.parse(cached);
    }
    else {
      // No value in the cache, so load it from spreadsheet
      var data = SpreadsheetApp.getActive().getSheetByName("Sheet A").getDataRange().getValues();
      this.myGlobalArray = {};
      for (var row=0; row<data.length; row++) {
        this.myGlobalArray[data[row][0]] = data[row][6];
      }

      // Stringify and store the global into the cache
      cache.put("myGlobalArray", JSON.stringify(this.myGlobalArray));
    }
  }
}

编辑:关联数组

onEdit()内的评论中表示:

//if selected value is name1, populate myGolbalArray[Name1] value in Amount

这意味着 myGlobalArray 是一个 关联数组 ,其中索引是一个非整数值。此要求现在反映在从电子表格读取时 this.myGlobalArray 的填充方式。

for (var row=0; row<data.length; row++) {
  this.myGlobalArray[data[row][0]] = data[row][6];
  //                 ^^^^^^^^^^^^    ^^^^^^^^^^^^
  //  Name ---------------/           /
  //  Amount ------------------------/
}

关于 Javascript 数组的不同风格已经写了很多,例如 Javascript Associative Arrays Demystified


1 实际上,只有具有全局范围的函数才能将 this 理解为 "global to the script"。包含在对象内部的函数会将 this 解释为仅表示它们的宿主对象。但这是另一天的故事。

每次调用您的脚本都会创建一个新的脚本实例,它有自己独特的全局变量。每次调用脚本时,您实际上都会找到该特定实例的全局 "this"。您将 PropertyService 视为保存数据的持久方式是正确的。

马上我看到你的 globalArray 设置不正确:

var myGlobalArray = [];

需要

 var myGlobalArray = {};
 myGlobalArray['name1'] = 1
 myGlobalArray['name2'] = 2
 myGlobalArray['name3'] = 3

 //myGlobalArray = {name3=3.0, name1=1.0, name2=2.0}
 var stringArray =  JSON.stringify(myGlobalArray)
 //{"name1":1,"name2":2,"name3":3};

现在可以将其保存到 属性 商店并从中读取。

PropertiesService.getScriptProperties().setProperty("NameArray", stringArray);
stringArray = PropertiesService.getScriptProperties().getProperty("NameArray");
myGlobalArray = JSON.parse(stringArray);
Logger.log(myGlobalArray['name1']) // returns 1