JS宏官方API文档:https://qn.cache.wpscdn.cn/encs/doc/office_v19/index.htm
批量创建工作表/簿
批量创建工作表:
function批量创建工作表(){for(var city of["成都","上海","北京"]){let sht = Worksheets.Add();
sht.Name = city;}}
批量创建工作簿:
function批量创建工作簿(){for(var city of["成都","上海","北京"]){
book = Workbooks.Add();
book.SaveAs(`E:/tmp/${city}`);
book.Close();}}
若book.SaveAs不传入全路径,则默认可能保存到我的文档文件夹中。
批量拆分工作表到工作簿
数据如下:
执行代码:
function批量拆分工作表(){for(var sh of Sheets){// 如果既不指定 Before 也不指定 After,则新建一个工作簿,其中包含复制的工作表。
sh.Copy();
ActiveWorkbook.SaveAs(`E:/VBA/wps/${sh.Name}.xlsx`);
ActiveWorkbook.Close();}}
分解出3个独立的文件:
批量判断处理单元格数据
数据和需求如下:
简单的方法就是直接筛选再复制粘贴,但是现在我们需要完全基于js宏的语法实现:
function分数筛选(){var Arr1=[];var Arr2=Range("a2:b13").Value();for(var row of Arr2){if(row[1]>=100){
Arr1.push(row);}}Range("d4").Resize(Arr1.length,2).Value2=Arr1
}
运行后:
工资条制作
数据如下:
执行如下代码:
function工资条制作(){
Application.DisplayAlerts=false;let src=Sheets("工资表");for(let sht of Sheets){if(sht.Name=="结果") sht.Delete();}
Application.DisplayAlerts=true;var sht=Worksheets.Add();
sht.Name="结果";for(i=0;i<10;i++){
src.Range("a1:m4").Copy();
sht.Cells.Item(5*i+1,1).PasteSpecial();
src.Range(`A${i+5}:M${i+5}`).Copy();
sht.Cells.Item(5*i+5,1).PasteSpecial();}
sht.Activate()}
拆分结果:
注意:如果原表不止10人,则修改循环次数即可。
如果允许直接在原表上修改,可以使用相对引用录制宏得到代码:
function工资条制作2(){Range("a1:m4").Select();for(var i=1;i<=9;i++){
Selection.Copy();
ActiveCell.Offset(5,0).Range("A1:M4").Insert(xlShiftDown,undefined);
Application.CutCopyMode =false;
ActiveCell.Offset(5,0).Range("A1:M4").Select();}}
任意多列SN号合并到一列
原数据都是如下格式的SN号:
下面我们考虑通过宏代码合并到一列,代码如下:
function单表多列合并到一列新文件(){var vs=Range("A1").CurrentRegion.Value().flat();// 过滤掉空值并去重
vs=Array.from(newSet(vs.filter(v=>v!=undefined)));// 一维数组默认赋值给一行,赋值给一列需要先转置二维
vs = WorksheetFunction.Transpose(vs);var wb = Workbooks.Add();
wb.Sheets(1).Range("A1").Resize(vs.length,1).Value2 = vs;}
注意:上面的代码使用JavaScript的语法对数组进行了去重。
Array.from(newSet(arr))
过滤空值:
arr.filter(v=>v!=undefined)
最终得到一列:
批量合并工作表并添加来源表名
原数据:
执行代码:
function合并工作表数据(){var NewArr=[],n=1;for(var ws of Sheets){var Arr=ws.Range("a1").CurrentRegion.Value();if(n++==1){var title=Arr[0].concat("工作表名")};delete Arr[0]
Arr.forEach(ar=>NewArr.push(ar.concat(ws.Name)));}
NewArr.unshift(title);var wb=Workbooks.Add();
wb.Sheets(1).Range("a1").Resize(NewArr.length,NewArr[0].length).Value2=NewArr;}
成功合并得到如下结果:
语音朗读
代码如下:
function Workbook_Open(){
Application.Speech.Speak("美好的一天就从这一刻开始吧!",true)}
function Workbook_NewSheet(Sh){
Application.Speech.Speak("果然狠人老表,区区几张sheet是不够你消遣的!",true)}
function Application_WorkbookBeforeClose(Wb, Cancel){
Application.Speech.Speak("就想问老板,可以下班了吗?")}
function Application_SheetSelectionChange(Sh, Target){if(Sh.Name!="词汇"|Target.Value()==undefined)return;
Application.Speech.Speak(Target.Value());}
保存上面的代码后,当打开或关闭该文件或新建工作表都会朗读对应的文字。
对于词汇这张工作表,点击任何有值的单元格都会对其进行朗读。
Application.Speech.Speak
第二个参数传入true表示异步,默认为同步。
富文本弹窗
alert函数支持传入HTML:
functiontestAlert_CSS(){let foo =`
<h3 style="color:red">Hi</h3>
<p style="color:green;text-shadow: 1px 1px 2px red, 0 0 1em blue, 0 0 0.2em blue;">
Hi ${newDate().toLocaleDateString()}
</p>`;alert(foo)}
执行效果:
判断目标是否在指定区域内
function_m_isInArea(uArea,cell){
uArea =typeof(uArea)=="string"?Range(uArea):uArea;
cell =typeof(cell)=="string"?Range(cell):cell;if(uArea.Parent.Name!=cell.Parent.Name)returnfalse;let s_row=uArea.Row,e_row=s_row+uArea.Rows.Count-1;let s_col=uArea.Column,e_col=s_col+uArea.Columns.Count-1;let t_row = cell.Row,t_col = cell.Column;// Console.log(`${s_row}-${e_row},${s_col}-${e_col},(${t_row},${t_col})`);return s_row<=t_row && t_row<=e_row && s_col<=t_col && t_col<=e_col;}function_m_test(){
Console.log(_m_isInArea("A2:C20","B3"));
Console.log(_m_isInArea("A2:C20","D3"));}
结果:
true
false
本地文件读写
functionread_write_data_txt(){let txtFile ="E:/tmp/a.txt";let f =FreeFile();Open(txtFile,f,jsOutput,jsWrite);Write(f,"123");Write(f,"456,789");Write(f,"aaa,bbb");Close();
Console.clear()let fNumber =FreeFile()Open(txtFile, fNumber,jsInput)while(!EOF(fNumber)){let p=LineInput(fNumber);
Console.log(p)}Close(fNumber)}
"123"
"456,789"
"aaa,bbb"
生成文件:
JavaScript语法补充
undefined和null的区别
undefined和null的区别(值相等,但类型不等) :
typeofundefined// undefinedtypeofnull// objectnull===undefined// falsenull==undefined// true
typeof操作符
typeof 操作符可以检测变量的数据类型 :
typeof"John"// 返回 string typeof3.14// 返回 numbertypeofNaN// 返回 numbertypeoffalse// 返回 booleantypeof[1,2,3,4]// 返回 objecttypeof{name:'John',age:34}// 返回 objecttypeofnewDate()// 返回 objecttypeoffunction(){}// 返回 functiontypeof myCar // 返回 undefined (如果 myCar 没有声明)typeofnull// 返回 object
解构赋值
var[x, y, z]=['hello','JavaScript','ES6'];
console.log('x = '+ x +', y = '+ y +', z = '+ z);// x = hello, y = JavaScript, z = ES6[x,[y, z]]=['hello',['JavaScript','ES6']];
console.log('x = '+ x +', y = '+ y +', z = '+ z);// x = hello, y = JavaScript, z = ES6
数组常用方法
方法描述concat()连接两个或更多的数组,并返回结果。copyWithin()从数组的指定位置拷贝元素到数组的另一个指定位置中。entries()返回数组的可迭代对象。every()检测数值元素的每个元素是否都符合条件。fill()使用一个固定值来填充数组。filter()检测数值元素,并返回符合条件所有元素的数组。find()返回符合传入测试(函数)条件的数组元素。findIndex()返回符合传入测试(函数)条件的数组元素索引。forEach()数组每个元素都执行一次回调函数。from()通过给定的对象中创建一个数组。includes()判断一个数组是否包含一个指定的值。indexOf()搜索数组中的元素,并返回它所在的位置。isArray()判断对象是否为数组。join()把数组的所有元素放入一个字符串。keys()返回数组的可迭代对象,包含原始数组的键(key)。lastIndexOf()搜索数组中的元素,并返回它最后出现的位置。map()通过指定函数处理数组的每个元素,并返回处理后的数组。pop()删除数组的最后一个元素并返回删除的元素。push()向数组的末尾添加一个或更多元素,并返回新的长度。reduce()将数组元素计算为一个值(从左到右)。reduceRight()将数组元素计算为一个值(从右到左)。reverse()反转数组的元素顺序。shift()删除并返回数组的第一个元素。slice()选取数组的的一部分,并返回一个新数组。some()检测数组元素中是否有元素符合指定条件。sort()对数组的元素进行排序。splice()从数组中添加或删除元素。unshift()向数组的开头添加一个或更多元素,并返回新的长度。
splice:
splice()
方法可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:
var arr =['Microsoft','Apple','Yahoo','AOL','Excite','Oracle'];// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2,3,'Google','Facebook');// 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr;// ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']// 只删除,不添加:
arr.splice(2,2);// ['Google', 'Facebook']
arr;// ['Microsoft', 'Apple', 'Oracle']// 只添加,不删除:
arr.splice(2,0,'Google','Facebook');// 返回[],因为没有删除任何元素
arr;// ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
concat:
concat()
方法把当前的
Array
和另一个
Array
连接起来,并返回一个新的
Array
:
var arr =['A','B','C'];var added = arr.concat([1,2,3]);
added;// ['A', 'B', 'C', 1, 2, 3]
arr;// ['A', 'B', 'C']
请注意,
concat()
方法并没有修改当前
Array
,而是返回了一个新的
Array
。
实际上,
concat()
方法可以接收任意个元素和
Array
,并且自动把
Array
拆开,然后全部添加到新的
Array
里:
var arr =['A','B','C'];
arr.concat(1,2,[3,4]);// ['A', 'B', 'C', 1, 2, 3, 4]
join:
join()
方法把当前
Array
的每个元素都用指定的字符串连接起来,然后返回连接后的字符串:
var arr =['A','B','C',1,2,3];
arr.join('-');// 'A-B-C-1-2-3'
如果
Array
的元素不是字符串,将自动转换为字符串后再连接。
map函数遇到的问题
map的语法:
array.map(function(currentValue,index,arr), thisValue)
- currentValue: 当前元素的值
- index : 当前元素的索引值
- arr : 前元素属于的数组对象
- thisValue:用作 “this” 的值。如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
利用
map()
把字符串变成整数 :
var arr =['1','2','3'];var r = arr.map(parseInt);
console.log(r);//结果却是1, NaN, NaN
这是因为parseInt接受两个参数
(string, radix)
,第二个参数指定被转换的“数字”多少进制。
当
arr = [1,2,3]
时,
arr.map(parseInt)
实际为:
parseInt('1',0);// 按十进制转换'1'parseInt('2',1);// 按一进制转换'2',但一进制中只有0没有1parseInt('3',2);// 按二进制转换3,但二进制中只有0和1没有2
解决办法:
var arr =['1','2','3'];var r = arr.map(str=>parseInt(str));
console.log(r);// 结果:1,2,3
模板字符串
var name ='小华';var age =20;var message =`你好, ${name}, 你今年${age}岁了!`;
循环语句
for循环
语法:
for(语句 1; 语句 2; 语句 3){
被执行的代码块
}
- 语句1 (代码块)开始前执行
- 语句2 定义运行循环(代码块)的条件
- 语句3 在循环(代码块)已被执行之后执行
for(var i=0,len=cars.length; i<len; i++){
document.write(cars[i]+"<br>");}// 或var i=2,len=cars.length;for(; i<len; i++){
document.write(cars[i]+"<br>");}
for…in循环
for/in 语句循环遍历对象的属性:
var person={fname:"John",lname:"Doe",age:25};for(x in person)// x 为属性名{
txt=txt + person[x];}
循环遍历
Array
的索引:
var a =['A','B','C'];for(var i in a){
console.log(i);// '0', '1', '2'
console.log(a[i]);// 'A', 'B', 'C'}
注意:
for ... in
对
Array
的循环得到的是
String
而不是
Number
。
for…of循环
具有
iterable
类型的集合还可以通过
for ... of
循环来遍历,它是ES6引入的新的语法。
var a =['A','B','C'];var s =newSet(['A','B','C']);var m =newMap([[1,'x'],[2,'y'],[3,'z']]);for(var x of a){// 遍历Array
console.log(x);}for(var x of s){// 遍历Set
console.log(x);}for(var x of m){// 遍历Map
console.log(x[0]+'='+ x[1]);}
for of
循环和
for in
循环的区别
for ... in
循环遍历的实际是对象的属性名称,手动给Array对象添加了额外的属性后:
当我们手动给
Array
对象添加了额外的属性后,
for ... in
循环将带来意想不到的意外效果:
var a =['A','B','C'];
a.name ='Hello';for(var x in a){
console.log(x);// '0', '1', '2', 'name'}
for ... of
循环则只循环集合本身的元素:
var a =['A','B','C'];
a.name ='Hello';for(var x of a){
console.log(x);// 'A', 'B', 'C'}
iterable
内置的
forEach
方法
var a =['A','B','C'];
a.forEach(function(element, index, array){// element: 指向当前元素的值// index: 指向当前索引// array: 指向Array对象本身
console.log(element +', index = '+ index);});var s =newSet(['A','B','C']);//Set没有索引,因此回调函数的前两个参数都是元素本身
s.forEach(function(element, sameElement,set){
console.log(element);});var m =newMap([[1,'x'],[2,'y'],[3,'z']]);//Map的回调函数参数依次为value、key和map本身
m.forEach(function(value, key, map){
console.log(value);});
回调函数可以省略参数:
var a =['A','B','C'];
a.forEach(function(element){
console.log(element);});
while 循环
语法:
while(条件){
需要执行的代码
}// 或do{
需要执行的代码
}while(条件);
例子:
while(i<5){
x=x +"The number is "+ i +"<br>";
i++;}do{
x=x +"The number is "+ i +"<br>";
i++;}while(i<5);
箭头函数与装饰器
ES6 新增了箭头函数,语法 :
(参数1, 参数2, …, 参数N)=>{ 函数声明 }单一参数=>{函数声明}()=>{函数声明}
例子:
constx=(x, y)=> x * y;constx=(x, y)=>{return x * y };
箭头函数简化了函数定义,如果只包含一个表达式,可以省略
{ ... }
和
return
。
如果要返回一个对象,单表达式会报错:
// SyntaxError:x=>{foo: x }
因为和函数体的
{ ... }
有语法冲突,所以要改为:
// ok:x=>({foo: x })
箭头函数看上去是匿名函数的一种简写,但有个明显的区别:箭头函数内部的
this
是词法作用域,由上下文确定。
箭头函数的
this
总是指向词法作用域,也就是外层调用者
obj
:
var obj ={birth:1990,getAge:function(){var b =this.birth;// 1990varfn=()=>newDate().getFullYear()-this.birth;// this指向obj对象returnfn();}};
obj.getAge();// 25
由于
this
在箭头函数中已经按照词法作用域绑定了,所以,用
call()
或者
apply()
调用箭头函数时,无法对
this
进行绑定,即传入的第一个参数被忽略:
var obj ={birth:2000,getAge:function(year){var b =this.birth;// 1990varfn=(y)=> y -this.birth;// this.birth仍是2000returnfn.call({birth:2010}, year);}};
obj.getAge(2015);// 15
在一个独立的函数调用中,根据是否是strict模式,
this
指向
undefined
或
window
。
要指定函数的
this
指向哪个对象,可以用函数本身的
apply
方法,它接收两个参数,第一个参数就是需要绑定的
this
变量,第二个参数是
Array
,表示函数本身的参数。
用
apply
修复
getAge()
调用:
functiongetAge(){var y =newDate().getFullYear();return y -this.birth;}var xiaoming ={name:'小明',birth:1990,age: getAge
};
xiaoming.age();// 25getAge.apply(xiaoming,[]);// 25, this指向xiaoming, 参数为空
利用
apply()
可实现装饰器,比如想统计一下代码一共调用了多少次:
'use strict';var count =0;var oldParseInt = parseInt;// 保存原函数
window.parseInt=function(){
count +=1;returnoldParseInt.apply(null, arguments);// 调用原函数};parseInt('10');parseInt('20');parseInt('30');
console.log('count = '+ count);// 3
call()
与
apply()
类似,唯一区别是:
apply()
把参数打包成Array
再传入;call()
把参数按顺序传入。
比如调用
Math.max(3, 5, 4)
,分别用
apply()
和
call()
实现如下:
Math.max.apply(null,[3,5,4]);// 5
Math.max.call(null,3,5,4);// 5
对普通函数调用,通常把
this
绑定为
null
。
版权归原作者 小小明-代码实体 所有, 如有侵权,请联系我们删除。