目录
学习目标
- 掌握WPS Excel JS入门知识
- 使用JS脚本提升自动化办公水平
- 以"万物皆可为对象"的思维学习(对象包含属性和方法)
入门准备
- 参考资料WPS开放平台
- 参考资料W3school
- 参考资料MrFlySand-飞沙. (2021). WPS JS宏教程文档,0基础入门,超详细~. [在线]. 博客园博客
- 启用
开发工具
切换宏编辑器到JS开发环境
点滴笔记
1、录制宏与自定义函数区别
自定义函数和宏基本类似,主要不同点:
①.它们执行计算而不是操作,所以某些类型的语句,例如设置单元格的值、修改选区等不建议写在自定义函数中
②.宏通常不会有参数和返回值,而函数在参数上没有限制,往往是有返回值的
但在我看来,也没有那么死板,应该像编程一样自由设计模块。我们知道,录制宏是WPS Excel官方自带的,它能通过宏录制器捕捉用户与WPS交互的操作,并以JS代码形式记录下来,因此录制宏时常用来寻找写JS脚本的灵感
2、JS样式指南
代码约定确保代码质量,既可以改善代码可读性,也可以提升代码可维护性
- 变量和函数一般使用小驼峰法标识(即除第一个单词之外,其他单词首字母均大写),比如lastName、fullPrice等;或者全小写字母,通过下划线连接起来,比如my_function、my_error等
- 全局变量、常量通常为大写
- 严格区分字母大小写,不可以用数字开头
- 始终在运算符( = + - * / )周围以及逗号之后添加空格
- 代码块缩进始终使用 4 个空格
- 简单语句始终以分号结束单条语句,复杂语句通用规则:
①.将左花括号放在第一行的结尾
②.左花括号前添加一空格
③.将右花括号独立放在一行
④.以分号结束一个复杂的声明- 对象定义通用规则:
①.将左花括号与类名放在同一行
②.冒号与属性值间有个空格
③.字符串使用双引号,数字不需要
④.最后一个属性-值对后面不要添加逗号
⑤.将右花括号独立放在一行,并以分号作为结束符号- 建议每行长度小于80个字符,换行的最佳位置是在运算符或逗号之后
3、自定义函数结构
关键字:function
函数名:支持中英文
标点符号:在英文输入法下使用各标点符号
function 计算面积(长, 宽)
{
if (宽 == undefined)
return 长*长
else
return 长*宽
}
function areaCalculation(length, width)
{
if (width== undefined)
return length*length
else
return length*width
}
4、常见基本语法
- WPS JS脚本每条语句后面要么都有";“,要么都没有”;",保持统一风格,脚本运行不会报错
- 不同对象优先级,Application > Workbooks > Sheets > Range/Cells
- var、let与const声明的变量区别:
① var 变量的作用域在函数体内或者函数之外全局范围内,可以在声明之前使用,未声明变量的值为undefined
② let 变量的作用域在所在语句的代码块内,未声明直接使用系统会报错;在相同作用域内,不允许重复声明同一个变量
③ const 声明一个只读常量,声明之后不允许改变其值。因此,const 一旦声明必须初始化,否则会报错- JavaScript 变量属于本地或全局作用域,全局变量可以通过闭包实现局部私有,局部变量只能用于其被定义的函数内部;拥有相同名称的全局变量和局部变量是不同的变量
4.1 工作簿
Application.Workbooks.Add() // 表示新建一个工作簿
Application.Workbooks.Open(路径+文件名) // 表示打开指定工作簿
Application.Workbooks.Item(n) // 表示选中第n个已打开的工作簿
Application.Workbooks.Item("xxx.xlsx") // 表示选中某个已打开的工作簿
Application.Workbooks.Item(n).Activate() // 表示激活第几个已打开的工作簿
Application.Workbooks.Item("xxx.xlsx").Activate() // 表示激活指定的工作簿
Application.Workbooks.Item(n).Save() // 表示保存当前工作簿
Application.Workbooks.Item(n).SaveAs(路径+文件名) // 表示另存为新的工作簿
Application.Workbooks.Item(n).Close() // 表示关闭当前workbook对象
4.2 工作表
Sheets.Item(1) // 表示选中第1个工作表,n表示第n个子表
Sheets.Item("xxx") // 选中指定名字的工作表
... // (其他属性和方法请参考官方文档)
4.3 单元格
// 选取单元格
ActiveSheet.Cells.Select() // 全选当前活动表所有单元格
Range("D1:V45") // 选择指定区域单元格
Range("A"+2) // 选择A2单元格
Cells.Item(i,j) // 选择某个单元格
// 读取或设置单元格的值
Range("D1:V45").Value2 // 获取指定区域单元格的值,Value2可用于单元格赋值
Range("D1:V45").Value() // 获取指定区域单元格的值,不可用于单元格赋值
// 设置字体和单元格背景
Range("E7").Select(); // 选中单元格
Selection.Formula = "999"; // 单元格赋值
(obj=>{
obj.Color = 255; // 设置字体颜色
obj.TintAndShade = 0; // 设置颜色变深或变浅,0为中间值,1为最亮,-1为最暗
})(Selection.Font);
Selection.Font.Bold = true; // 设置文字加粗
Selection.HorizontalAlignment = xlHAlignCenter; // 设置文字水平居中
(obj=>{
obj.Pattern = xlPatternSolid; // xlPatternSolid代表纯色
obj.ThemeColor = 8; // 返回或设置已应用配色方案中的主题颜色
obj.TintAndShade = 0.800000;
obj.PatternColorIndex = -4105; // 返回或设置内部图案颜色,-4105表示excel自动控制图案
})(Selection.Interior); // Interior对象设置单元格背景颜色
Selection.Font.Name = "微软雅黑"; // 设置文字字体
Selection.Font.Size = 10; // 设置文字大小
// 合并与取消合并
Range("D5:I14").Select();
(obj=>{
obj.Merge(false); // 合并单元格,默认值false,true表示将指定区域中每一行的单元格合并为一个单独的合并单元格
obj.HorizontalAlignment = xlHAlignCenter; // 设置居中显示
})(Selection);
(obj=>{
obj.UnMerge(); // 取消单元格合并
obj.HorizontalAlignment = xlHAlignGeneral; // 按数据类型对齐
})(Selection);
4.4 条件语句
// if示例,&&表示逻辑与,||表示逻辑或
if (Range("A1").Value2 > Range("A2").Value2 && Range("A1").Value2 > Range("A3").Value2) {
alert("A1最大");
}
else if (Range("A1").Value2 > Range("A2").Value2 || Range("A1").Value2 > Range("A3").Value2) {
alert("A1大于A2、A3中某一个");
}
else {
alert("A1最小");
}
// switch示例
var a = 1;
switch (a) {
case 1:
alert("A") // 当表达式的结果等于 1 时,则执行该代码
break;
case 3:
alert("C") // 当表达式的结果等于 3 时,则执行该代码
break;
default :
alert("none") // 如果没有与表达式相同的值,则执行该代码
}
4.5 循环语句
JavaScript支持不同类型的循环:
- for -> 循环执行代码块一定次数
- for in -> 通过对象的键名遍历对象,可能会遍历到数组其他属性(比如length属性),迭代顺序不确定
- for of -> 更适合遍历可迭代对象的值,迭代顺序确定
- while -> 先判断条件再执行,当指定条件为 true 时循环指定的代码块
- do-while -> 先执行一次再判断条件,当指定条件为 true 时再循环指定的代码块
// for用法
var text="";
for (var i = 0; i < 5; i++) {
text += "数字是 " + i + "\n";
}
Debug.Print(text)
// for in用法(当顺序很重要时,最好使用 for 循环、for of 循环,不建议使用for in)
var person = {fname:"Bill", lname:"Gates", age:62};
var text = "";
for (let x in person) {
text += person[x] + " ";
}
Debug.Print(text)
// for of用法
var language = "JavaScript";
var text = "";
for (let x of language) {
text += x;
}
Debug.Print(text)
// while用法
let text = "";
let i = 0;
while (i < 10) {
if (i % 2 == 0) {
i++;
continue; // 跳过本次循环,继续下一次循环
}
else {
text += "奇数有 " + i + ' ';
i++;
}
}
Debug.Print(text)
// do while用法
let text = "";
let i = 0;
do {
if (i == 5) {
break; # 跳出当前循环
}
else {
text += "The number is " + i;
i++;
}
} while (i < 10);
Debug.Print(text)
4.6 typeof运算符
typeof 可以确定JS变量的数据类型(除了数组或日期)。在JavaScript 中有:
- 5 种包含值的数据类型:string、number、boolean、object、function
- 6 种类型的对象:Object、Date、Array、String、Number、Boolean
- 2 种不包含值的数据类型:null(可用来清空变量,比如persons= null)、undefined
constructor 属性返回所有JS变量的构造器函数
类型转换:Number() 转换数值,String()/xx.toString() 转换字符串,Boolean() 转换布尔值
typeof "Bill" // 返回 "string"
typeof 3.14 // 返回 "number"
typeof NaN // 返回 "number"
typeof false // 返回 "boolean"
typeof [1,2,3,4] // 返回 "object"
typeof {name:'Bill', age:19} // 返回 "object"
typeof new Date() // 返回 "object"
typeof function () {} // 返回 "function"
typeof myCar // 返回 "undefined"
typeof null // 返回 "object"
mylist = ["Bill".constructor, (3.14).constructor, false.constructor, [1,2,3,4].constructor,
{name:'Bill', age:62}.constructor, new Date().constructor, function () {}.constructor]
for (let l of mylist) {
Debug.Print(l)
}
// 列表各元素数据类型结果如下:
//function Number() { [native code] }
//function Boolean() { [native code] }
//function Array() { [native code] }
//function Object() { [native code] }
//function Date() { [native code] }
//function Function() { [native code] }
Debug.Print(mylist[3] == Array) // 判断是否是数组类型
Debug.Print(mylist[5] == Date) // 判断是否是日期类型
// JavaScript 变量均为对象,当声明了一个变量,就创建了一个新的对象
// 使用关键词 "new" 来声明变量类型
var carname = new String;
var x= new Number;
var y= new Boolean;
var cars= new Array;
var person= new Object;
4.7 比较运算符
4.8 正则表达式
正则表达式是构成搜索模式的字符序列,可用于文本搜索和文本替换操作。
语法:/正则表达式主体/修饰符(可选)
在JS中,常用的方法有:
① search() 用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置
② replace() 用于在字符串中用一些字符串替换另一些字符串,或替换第一个与正则表达式匹配的子串
③ test() 用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false
var str = "Hello World! World!";
var n = str.search(/World/i); // i是修饰符,表示搜索不区分大小写
Debug.Print(n)
var str = "Hello World! World!";
var res = str.replace(/world/ig, "JS"); // i、g是修饰符,表示全局匹配且不区分大小写
Debug.Print(str, res);
var patt = /e/;
var res = patt.test("The best things in life are free!");
Debug.Print(res)
4.9 异常处理
- try 语句能够测试代码块中的错误
- catch 语句允许处理错误
- throw 语句允许抛出错误或创建自定义错误
- finally 无论try语句是否引发异常,finally子句中的代码都会被执行,比如释放资源、关闭文件等
try {
// 供测试的代码块
if (xxx) throw "xxx"
}
catch (err) {
// 处理错误的代码块
}
finally {
// 无论结果如何都执行的代码块
}
// 举个栗子
function try_test() {
try {
// 这里写可能会引发异常的代码
throw new Error('这是我主动抛出的异常');
}
catch (error) {
// 这里写处理异常的代码
if (error instanceof Error) {
Debug.Print('捕获到异常:', error.message);
}
else {
Debug.Print('没有产生异常');
}
}
}
4.10 模板字符串
- 模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以定义多行字符串,更支持在字符串中嵌入变量或者表达式
- 模板字符串支持同时使用单引号和双引号
- 如果模板字符串表示多行字符串,则多行字符串中所有的空格和缩进都会被完整保留
- 如果想嵌入变量或者表达式,则使用 ${variable or expression} 表示
// 示例
`string text`
`He's often called "Runoob"`
`string text line 1
string text line 2`
`string text ${expression} string text`
4.11 Array(数组) 对象
数组是一种特殊的变量,用于在单一变量中存储多个值。在JS中,对象使用命名索引,数组使用数字索引,数组是特殊类型的JS对象
// 1、使用数组文本是创建JS数组最简单的方法。数组文本可横跨多行,空格和折行并不重要,数组最后一个元素之后不要写逗号!
var myCars=["Saab","Volvo","BMW"];
var myCars=[
"Saab",
"Volvo",
"BMW"
];
// 2、常规方式1(考虑到简洁、可读性和执行速度,不推荐此法,避免使用new Array)
var myCars=new Array();
myCars[0]="Saab";
myCars[1]="Volvo";
myCars[2]="BMW";
// 3、常规方式2(考虑到简洁、可读性和执行速度,不推荐此法,避免使用new Array)
var myCars=new Array("Saab","Volvo","BMW");
通过索引可以访问或修改数组元素
var carName = myCars[0]; // 访问第一个元素
myCars[0] = 'BYD'; // 修改第二个元素
常见数组属性和方法
myCars.length // 返回数组元素个数
delete myCars[0]; // 把myCars数组首个元素改为undefined,delete会在数组留下未定义的空洞
myCars.indexOf("Volvo"); // 返回"Volvo"值的索引号
myCars.toString(); // 把数组转换为逗号分隔的字符串
myCars.join("+"); // 将所有数组元素结合为一个字符串, 支持自定义分隔符
myCars.pop(); // 删除数组最后一个元素,同时返回“被弹出”的值
myCars.push(); // 在数组结尾处向数组添加一个新的元素,同时返回新数组的长度
myCars.shift(); // 删除首个数组元素,并把所有其他元素“位移”到更低的索引,同时返回被“位移出”的字符串
myCars.unshift("新元素"); // 在开头向数组添加新元素,并“反向位移”旧元素,同时返回新数组的长度
myCars.splice(插入位置从1开始算, 待删除元素个数, 待添加的新元素1, 待添加的新元素2...); // 向数组添加新项,同时返回一个包含已删除项的数组
myCars.concat(array1, array2, ...); // 合并(连接)多个数组,同时返回一个新数组,不会改变原数组
myCars.slice(开始位置从0开始算, 结束位置); // 用数组的某个片段创建新数组,不会从源数组中删除任何元素
myCars.reverse(); // 反转数组中的元素
myCars.sort(); // 按字母顺序对数组进行排序
// JS不提供查找数组中最大或最小值的内置函数
var points = [40, 100, 1, 5, 25, 10];
// 方法1:对数组排序,间接获得最大、最小值
points.sort(function(a, b){return a - b}); // 通过比值函数实现数组升序排序
points[0]; // 取最小值
points.sort(function(a, b){return b - a}); // 通过比值函数实现数组降序排序
points[0]; // 取最大值
// 方法:2:调用Math的方法
max_value = Math.max.apply(null, arr); // 查找数组最大值
min_value = Math.min.apply(null, arr); // 查找数组最小值