我一直试图在Google应用脚本中(在电子表格内)获取一些功能来修改全局变量,但我似乎无法弄明白。
基本上我想声明一个变量(在本例中为“globalTestVar”),并且每当两个函数中的一个(globalVarTestFunctionOne和2)启动时,该变量应该递增1。
问题是每次按下按钮时都会再次声明变量,即使if(typeof(globalTestVar)=='undefined') - 语句应该处理它。
我习惯于Objective C和Java,我可以在开头声明我的变量,并在代码中的任何地方修改这些变量。
我很抱歉,如果这是一个基本问题,但我一直在谷歌搜索几个小时,我只是无法让它工作。
以下是代码:
logstuff("outside");
function logstuff(logInput){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var lastRow = sheet.getLastRow() + 1;
sheet.getRange("A"+lastRow).setValue(logInput);
return;
}
if (typeof(globalTestVar) == 'undefined') {
logstuff('declaring global variable');
globalTestVar = 0;
} else {
logstuff('global variable has been declared');
}
function globalVarTestUIFunction() {
var app = UiApp.createApplication().setTitle('Test UI');
var doc = SpreadsheetApp.getActive();
var formPanel = app.createVerticalPanel();
var buttonF1 = app.createButton('F1');
var buttonbuttonF1ClickHandler = app.createServerClickHandler("globalVarTestFunctionOne");
buttonF1.addClickHandler(buttonbuttonF1ClickHandler);
buttonbuttonF1ClickHandler.addCallbackElement(formPanel);
var buttonF2 = app.createButton('F2');
var buttonbuttonF2ClickHandler = app.createServerClickHandler("globalVarTestFunctionTwo");
buttonF2.addClickHandler(buttonbuttonF2ClickHandler);
buttonbuttonF2ClickHandler.addCallbackElement(formPanel);
app.add(formPanel);
formPanel.add(buttonF1);
formPanel.add(buttonF2);
doc.show(app);
return app;
}
function globalVarTestFunctionOne() {
logstuff('globalVarTestFunctionOne');
globalTestVar++;
logstuff('Value of globalTestVar: ' + globalTestVar);
}
function globalVarTestFunctionTwo() {
logstuff('globalVarTestFunctionTwo');
globalTestVar++;
logstuff('Value of globalTestVar: ' + globalTestVar);
}
输出:
我已经编写了自己的函数“logstuff”来打印消息,因为我不喜欢内置的Logger.log函数。
谢谢!
答案 0 :(得分:12)
您不会喜欢这样:GAS中的全局变量是静态的 - 您无法更新它们并期望它们保留它们的值。我也用谷歌搜索了几个小时。
您可以使用CacheService
或ScriptDB
作为此类问题的存储空间。 CacheService
快速且易于使用,但有限,因为缓存最终会过期。我还没有尝试过ScriptDB
答案 1 :(得分:10)
目前(2015年),我认为要采用的方法是使用课程PropertiesService和返回类型Properties。
据我了解,脚本函数的每次新调用(时间触发器,用户单击菜单项,按下按钮等)都将导致脚本的新完整解析,而不会记住先前的执行,除非它们是以某种方式持续存在(例如在电子表格范围内或使用Properties
)。
答案 2 :(得分:0)
尽管CacheService可以运行,但它的最长使用寿命为6小时。 可以通过使用PropertiesService来解决,如@consideRatio所述。
示例包装器可能是(将变量注入全局上下文)
/* Wrap variable inside global context */
const Globals = {
global:this,
items:{},
/* Can be 'User', 'Script', or 'Document'
** Script - same values for all executions of this script
** User - same values for all executions by same user
** Document - same values for any user for same document
** Check reference for details.
** https://developers.google.com/apps-script/guides/properties
**
*/
context:'Script',
/* Get property service based on requested context */
get service() {
return PropertiesService['get' + this.context + 'Properties']()
},
/* Assign implementation */
set(name, value = null) {
this.service.setProperty(name, JSON.stringify(value));
return value;
},
/* Read implementation */
get(name) {
var value = this.service.getProperty(name);
return value !== null? JSON.parse(value) : null;
},
/* Shortcut for setter of complex objects */
save(name) {
this.set(name, this.items[name]);
},
/* Save all */
flush(name) {
Object.keys(this.items).map(name => this.save(name));
},
/* Delete implementation */
reset(name) {
this.service.deleteProperty(name);
delete this.items[name];
},
/* Add to global scope */
init(name, default_value = null) {
if(! this.items.hasOwnProperty(name)) {
if(this.service.getProperty(name) === null)
this.set(name, default_value);
this.items[name] = this.get(name);
Object.defineProperty(this.global, name, {
get: () => {return this.items[name]},
set: (value) => {return this.items[name] = this.set(name, value)},
})
}
return this.items[name];
}
}
在Globals.init中注册后,可以像使用普通vars一样使用变量。但是,由于原始对象不支持观察者,因此必须在脚本末尾或显式刷新它们。
/* In case you need to start over */
function restart_simulations() {
Globals.reset('counter');
Globals.reset('state');
test_run();
}
function test_run() {
/* After running init once, you can use global var as simple variable */
Globals.init('counter', 1); // Required to use "counter" var directly, as simple variable
/* Complex objects are also accepted */
Globals.init('state', { logined: false, items: [] });
/* Using primitives is simple */
Logger.log('Counter was ' + counter);
counter = counter + 1;
Logger.log('Counter is now ' + counter);
/* Let's modify complex object */
Logger.log('State was ' + JSON.stringify(state));
state.items.push(state.logined ? 'foo' : 'bar');
state.logined = ! state.logined;
Logger.log('State is now ' + JSON.stringify(state));
/* Unfortunately, watchers aren't supported. Non-primitives have to be flushed */
/* Either explicitly */
//Globals.save('state');
/* Or all-at-once, e.g. on script end */
Globals.flush();
}
这是在3次运行之间保留的内容
First run:
[20-10-29 06:13:17:463 EET] Counter was 1
[20-10-29 06:13:17:518 EET] Counter is now 2
[20-10-29 06:13:17:520 EET] State was {"logined":false,"items":[]}
[20-10-29 06:13:17:523 EET] State is now {"logined":true,"items":["bar"]}
Second run:
[20-10-29 06:13:43:162 EET] Counter was 2
[20-10-29 06:13:43:215 EET] Counter is now 3
[20-10-29 06:13:43:217 EET] State was {"logined":true,"items":["bar"]}
[20-10-29 06:13:43:218 EET] State is now {"logined":false,"items":["bar","foo"]}
Third run:
[20-10-29 06:14:22:817 EET] Counter was 3
[20-10-29 06:14:22:951 EET] Counter is now 4
[20-10-29 06:14:22:953 EET] State was {"logined":false,"items":["bar","foo"]}
[20-10-29 06:14:22:956 EET] State is now {"logined":true,"items":["bar","foo","bar"]}
您可以在此处查看工作示例。