[TOC] > Fri Apr 23 2021 23:43:19 GMT+0800 (GMT+08:00) 大家在写 JS宏 的时候会碰到一些奇奇怪怪的问题,这里粗略做一些解答 ## 代码上下文带来的问题 > 最好不要关闭 WPS JS宏编辑器的那两个禁止项(1. 禁止全局作用域表达式;2. 禁止全局作用域标识符重复定义),它们还是能帮你规避一些因为代码上下文带来的问题。 来看一个例子: ```js /* 新增一个工作表: 1. 位置: 最后一个工作表后面; 2. 将新工作表命名为 "mySheet" */ function _m_addNewSheet(){ let shCount = Worksheets.Count Worksheets.Add(null,Worksheets.Item(shCount)) Worksheets.Item(shCount).Name = "mySheet" } ``` 例子中哪里出了问题? * `let shCount = Worksheets.Count` 获取工作表个数。 * `Worksheets.Add(null,Worksheets.Item(shCount))` 新增一个工作表,此时工作表个数已经发生变化,但因为上下文的关系 `shCount` 依旧是没有新增工作表之前的个数。 * `Worksheets.Item(shCount).Name = "mySheet"` 因为 `shCount` 没有变,所以是倒数第二个工作表被命名为"mySheet",新建的那个工作表是默认名。 ### 如何更改? * 删掉 shCount ```js function _m_addNewSheet(){ Worksheets.Add(null,Worksheets.Item(Worksheets.Count)) Worksheets.Item(Worksheets.Count).Name = "mySheet" } ``` * 再次赋值 ```js function _m_addNewSheet(){ let shCount = Worksheets.Count Worksheets.Add(null,Worksheets.Item(shCount)) shCount = Worksheets.Count // 再次赋值(更新值) Worksheets.Item(shCount).Name = "mySheet" } ``` * +1 ```js function _m_addNewSheet(){ let shCount = Worksheets.Count Worksheets.Add(null,Worksheets.Item(shCount)) Worksheets.Item(shCount+1).Name = "mySheet" } ``` * shCount 函数化 > 在内部定义 ```js function _m_addNewSheet(){ let shCount = ()=>Worksheets.Count // 等效于 function(){return Worksheets.Count} Worksheets.Add(null,Worksheets.Item(shCount())) Worksheets.Item(shCount()).Name = "mySheet" } ``` > 在外部定义 ```js function _m_shCount(){ return Worksheets.Count } function _m_addNewSheet(){ Worksheets.Add(null,Worksheets.Item(_m_shCount())) Worksheets.Item(_m_shCount()).Name = "mySheet" } ``` * 异步化——不推荐,没看出来有什么意义。 ```js async function _m_addSheet(){ let shCount = Worksheets.Count // 开始之前先获取工作表数量 return new Promise((res,rej)=>{ Worksheets.Add(null,Worksheets.Item(shCount)) // 判断是否新增完成 if(Worksheets.Count > shCount){ res(true) }else{ rej() } }) } // 下面这部分是多余的,因为前面的 async 是可以直接执行的…… function _m_test(){ _m_addSheet().then(()=>{ Worksheets.Item(Worksheets.Count).Name = "mySheet" }).catch(e=>{ Console.log(e) }) } ``` 对于那些值会改变的属性,在使用的时候应该注意这种上下文导致的问题,如何避免: 1. 每次使用的时候都使用属性本身——不将其赋值给变量 2. 嫌直接使用API太长,可以将其函数化处理——利用函数调用时执行的特点,尽可能实现和直接用API结果一致。 > 毕竟平时写宏都是一些小片段(代码量很少),没几个人会工程地化去弄一套宏(代码量很大)。因此能直接用API的地方还是直接用