避免重复:是否在 Google Apps 脚本中使用全局变量?
Avoid Repeating: Use Global Variables in Google Apps Script or Not?
截至 2021 年,使用 V8 引擎,我想知道在 Google Apps 脚本 中使用 全局变量是否是个好主意?如果是,如何使用它们?我的方法好吗(如下所述)?
当然,现在我检查了所有其他类似的问题。但是还有一些细节我没有找到:
基本上我试图做的是不重复代码:我有多个功能,我正在存储活动价差sheet和当前sheet之类的所以:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
这导致
- 重复 (1)
- 浪费资源 - 实例化 spreadsheet 和 sheet (2)
- 增加变量名称的不一致性(ss / spreadsheet / spreadSheet - 当 copy/pasting 来自网络上的片段时)(3)
对吗?
所以我想到在多个函数中有公共局部变量时使用全局变量 (GV)。
然而,由于它们将在每次函数调用时不必要地分配(还有其他不需要 GV 的函数),我尝试仅在需要时定义它们(仅当函数调用使用它们)——不使用定义关键字(var、const、let):
根据这个,这似乎是一个很好的方法(模式 1)。
无论如何,我想知道是否还有其他我不知道的注意事项或缺点?走这条路真的是个好主意吗?因为到目前为止,我没有看到任何实现这个的代码片段,我看到了很多GAS代码片段。
我知道的一个缺点是新的 GAS 编辑器缺少自动完成功能,对于我的 GV(因为我没有使用 'var' 或 'let' 来定义它们来设置它们的范围全球故意)。
否则,我知道 PropertiesService 和 CacheService。但是,我愿意将我的脚本(我定义 GV 的地方)重新用作其他脚本的库。
另外,您只能将值作为字符串存储在 PropertiesService 和 CacheService(而不是 SpreadsheetApp.getActiveSpreadsheet())中,对吗?更不用说我在脚本执行后不需要持久性。
所以我也犹豫要不要使用它们而不是 GV。
- 您可以在
中使用延迟加载技术
- 为了使其动态化并避免重复,您可以使用封闭箭头函数(
()=>{}
)来避免直接执行,并使用Object.defineProperty()
添加一个getter.
- 这种方法的显着优点之一是模块化延迟加载。如果不需要某个对象,则不会加载它。如果您将
ss
、sheet1
、sheet2
、rangeOfSheet1
和 rangeOfSheet2
作为全局变量,如果您访问 rangeOfSheet2
,则只会加载它的依赖项,即 sheet1
和 ss
。其余未动。
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
};
除了全局对象g
,我们还可以使用全局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
};
- 优点:您不必为变量添加前缀
g.
但是,全局 space 已被污染。
截至 2021 年,使用 V8 引擎,我想知道在 Google Apps 脚本 中使用 全局变量是否是个好主意?如果是,如何使用它们?我的方法好吗(如下所述)?
当然,现在我检查了所有其他类似的问题。但是还有一些细节我没有找到:
基本上我试图做的是不重复代码:我有多个功能,我正在存储活动价差sheet和当前sheet之类的所以:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
- 重复 (1)
- 浪费资源 - 实例化 spreadsheet 和 sheet (2)
- 增加变量名称的不一致性(ss / spreadsheet / spreadSheet - 当 copy/pasting 来自网络上的片段时)(3)
对吗?
所以我想到在多个函数中有公共局部变量时使用全局变量 (GV)。
然而,由于它们将在每次函数调用时不必要地分配(还有其他不需要 GV 的函数),我尝试仅在需要时定义它们(仅当函数调用使用它们)——不使用定义关键字(var、const、let):
根据这个
无论如何,我想知道是否还有其他我不知道的注意事项或缺点?走这条路真的是个好主意吗?因为到目前为止,我没有看到任何实现这个的代码片段,我看到了很多GAS代码片段。
我知道的一个缺点是新的 GAS 编辑器缺少自动完成功能,对于我的 GV(因为我没有使用 'var' 或 'let' 来定义它们来设置它们的范围全球故意)。
否则,我知道 PropertiesService 和 CacheService。但是,我愿意将我的脚本(我定义 GV 的地方)重新用作其他脚本的库。
另外,您只能将值作为字符串存储在 PropertiesService 和 CacheService(而不是 SpreadsheetApp.getActiveSpreadsheet())中,对吗?更不用说我在脚本执行后不需要持久性。
所以我也犹豫要不要使用它们而不是 GV。
- 您可以在
- 为了使其动态化并避免重复,您可以使用封闭箭头函数(
()=>{}
)来避免直接执行,并使用Object.defineProperty()
添加一个getter. - 这种方法的显着优点之一是模块化延迟加载。如果不需要某个对象,则不会加载它。如果您将
ss
、sheet1
、sheet2
、rangeOfSheet1
和rangeOfSheet2
作为全局变量,如果您访问rangeOfSheet2
,则只会加载它的依赖项,即sheet1
和ss
。其余未动。
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
};
除了全局对象g
,我们还可以使用全局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
};
- 优点:您不必为变量添加前缀
g.
但是,全局 space 已被污染。