AScript是一个开源的C#动态脚本解析执行引擎,支持扩展多种脚本语言,2026年7月14日正式发布了js脚本语言AScript.Lang.JavaScript,快来试试吧!
一、介绍
支持JavaScript基础语法和数据类型,以及数组、集合、字典、对象操作。
支持require引用模块。
二、安装
1 install-package AScript 2 install-package AScript.Lang.JavaScript
三、使用说明
1、注册语言
1 Script.Langs.Set("js", JavaScriptLang.Instance); 2 // 可全局设置为默认语言 3 // Script.Langs.Set("js", JavaScriptLang.Instance, setDefault: true);
2、定义函数
1 var s = @" 2 function sum(a,b) { 3 return a+b; 4 } 5 sum(10,20) 6 "; 7 var script = new Script(); 8 script.Context.Langs = new [] { "js" }; 9 var result = script.Eval(s); 10 Assert.AreEqual(30L, result);
3、正则表达式
js中使用 /{pattern}/{options} 格式表示正则表达式。
1 var script = new Script(); 2 script.Context.Langs = new[] { "js" }; 3 var result = script.Eval<List<object>>("'hello world World'.match(/world/gi)"); 4 Assert.AreEqual(2, result.Count); 5 Assert.AreEqual("world", result[0]); 6 Assert.AreEqual("World", result[1]);
4、解构
1)对象解构:支持默认值、别名、嵌套解构。
1 var s = @" 2 var {name, age} = {name: 'Alice', age: 25}; // name='Alice', age=25 3 var {a, b = 100} = {a: 10}; // a=10, b=100 4 var {inner: {name}} = {inner: {name: 'Tom', age: 20}}; // name='Tom' 5 var {name: aliasName} = {name: 'Bob'}; // aliasName='Bob' 6 "; 7 var script = new Script(); 8 script.Context.Langs = new[] { "js" }; 9 script.Eval(s);
2)数组解构:支持默认值、嵌套解构
1 var s = @" 2 var [x, y, z] = [10, 20, 30]; // x=10, y=20, z=30 3 var [x, , z] = [1, 2, 3]; // x=1, z=3 4 var [a = 5, b = 10] = [3]; // a=3, b=10 5 var [[inner], outer] = [[10], 20]; // inner=10, outer=20 6 "; 7 var script = new Script(); 8 script.Context.Langs = new[] { "js" }; 9 script.Eval(s);
3)混合解构:对象、数组混合解构
1 var script = new Script(); 2 script.Context.Langs = new[] { "js" }; 3 script.Eval("var [first, {name}] = [1, {name: 'John'}]"); 4 Assert.AreEqual(1L, script.Eval("first")); 5 Assert.AreEqual("John", script.Eval("name"));
5、字符串插值
1 var s = @" 2 var name='tom'; 3 `hello ${name}, 5+8=${5+8}` 4 "; 5 var script = new Script(); 6 script.Context.Langs = new [] { "js" }; 7 Assert.AreEqual("hello tom, 5+8=13", script.Eval(s));
6、字符串函数
1 String.fromCharCode(65,66,67); // 'ABC' 2 'hello'.startsWith('he'); // true 3 'hello'.endsWith('a'); // false 4 'hello'.includes('e'); // true 5 'hello'.indexOf('el'); // 1 6 'hello'.indexOf('el', 2); // -1 7 'hello'.lastIndexOf('l'); // 3 8 'hello'.search('el'); // 1 9 'hello'.search(/el/gi); // 1 10 'hello'.substr(-2); // 'lo' 11 'hello'.substr(-2,1); // 'l' 12 'hello'.substring(2); // 'llo' 13 'hello'.substring(2,4); // 'll' 14 'hello'.slice(2); // 'llo' 15 'hello'.slice(2,4); // 'll' 16 'hello'.slice(-3); // 'llo' 17 'hello'.slice(-3,-1); // 'll' 18 'Hello'.toLowerCase(); // 'hello' 19 'Hello'.toUpperCase(); // 'HELLO' 20 ' hello '.trim(); // 'hello' 21 ' hello '.trimStart(); // 'hello ' 22 ' hello '.trimEnd(); // ' hello' 23 'hello'.padStart(7); // ' hello' 24 'hello'.padStart(7, 'x'); // 'xxhello' 25 'hello'.padEnd(7); // 'hello ' 26 'hello'.padEnd(7, 'x'); // 'helloxx' 27 'hello'.charAt(1); // 'e' 28 'hello'.charCodeAt(1); // 101L 29 'hello tom, I am Tony'.match('to'); // ['to'] 30 'hello tom, I am Tony'.match(/to/); // ['to'] 31 'hello tom, I am Tony'.match(/to/gi); // ['to', 'To'] 32 'hello tom, I am Tony'.replace('to', 'x'); // 替换第1项:'hello xm, I am Tony' 33 'hello tom, I am Tony'.replaceAll('to', 'x'); // 替换所有项(区分大小写):'hello xm, I am Tony' 34 'hello tom, I am Tony'.replace(/to/g, 'x'); // 替换匹配项:'hello xm, I am Tony' 35 'hello tom, I am Tony'.replace(/to/gi, 'x'); // 替换匹配项:'hello xm, I am xny' 36 'a,b,c'.split(','); // ['a','b','c'] 37 'hello'.repeat(2); // 'hellohello' 38 'hello'.concat(' ', 'world'); // 'hello world'
7、创建数组
对应C#中的List<object>类型。
1 var s = @" 2 var arr1 = [1,2,3]; 3 var arr2 = new Array(1,2,3); 4 var arr3 = new Array(2); 5 "; 6 var script = new Script(); 7 script.Context.Langs = new[] { "js" }; 8 script.Eval(s); 9 var arr1 = script.Eval<List<object>>("arr1"); 10 Assert.AreEqual(3, arr1.Count); 11 Assert.AreEqual(1L, arr1[0]); 12 Assert.AreEqual(2L, arr1[1]); 13 Assert.AreEqual(3L, arr1[2]); 14 var arr3 = script.Eval<List<object>>("arr3"); 15 Assert.AreEqual(2, arr3.Count); 16 Assert.IsNull(arr3[0]); 17 Assert.IsNull(arr3[1]);
8、数组函数
1 [1, 2].concat([3, 4]); // [1, 2, 3, 4] 2 [1, 2, 3].join(','); // '1,2,3' 3 [1, 2, 3].indexOf(2); // 1 4 [1, 2, 3].includes(2); // true 5 [1, 2, 3].reverse(); // [3, 2, 1] 6 [1, 2, 3, 4, 5].filter(x => x % 2 == 0); // [2, 4] 7 [1, 2, 3].map(x => x * 2); // [2, 4, 6] 8 [1, 2, 3].reduce((acc, x) => acc + x); // 6 9 [1, 2, 3].reduce((acc, x) => acc + x, 10); // 16 10 [2, 4, 6].every(x => x % 2 == 0); // true 11 [1, 3, 5].some(x => x % 2 == 0); // false 12 [1, 2, 3].find(x => x > 1); // 2 13 [1, 2, 3].findIndex(x => x > 1); // 1 14 [1, 2, 3].fill(0); // [0, 0, 0] 15 [1, 2, 3].forEach(x => { }); // 遍历数组 16 [1, 2, 3].pop(); // 3 17 [1, 2, 3].push(5, 6, 7); // 数组结尾处理添加元素 18 [1, 2, 3].shift(); // 移除并返回首部元素 19 [1, 2, 3].unshift(5, 9, 10); // 从首部插入3个元素 20 [1, 2, 3, 4, 5].slice(2, 4); // 截取列表[2,4):[3, 4] 21 [1, 2, 3, 4, 5].splice(1, 2); // 截取并返回列表:[2, 3]
9、时间Date
对应C#中的DateTime类型。
1 new Date(); // 当前时间 2 Date.now(); // 当前时间戳 3 new Date(2026, 6, 4); // 2026-07-04 4 var time = new Date('2026-7-4'); 5 time.getYear(); // 获取年份-1900:126 6 time.getMonth(); // 获取月份-1:6 7 time.getDate(); // 获取月份中的天(1~31):4 8 time.getDay(); // 获取星期:6 9 time.getHours(); 10 time.getMinutes(); 11 time.getSeconds(); 12 time.getMilliseconds(); 13 time.getTime(); // 获取时间戳 14 time.toString('yyyy-MM-dd'); // '2026-07-04' 15 time.setFullYear(2025); 16 time.setFullYear(2025, 6); 17 time.setFullYear(2025, 6, 4); 18 time.setHours(21); 19 time.setMinutes(36); 20 time.setSeconds(15); 21 time.setMilliseconds(238);
10、字典Map
对应C#中的Dictionary<object, object>类型。
1 var m = new Map([['a', 1], ['b', 2], ['c', 3]]); 2 m.set('d', 4); 3 m.size; // 4 4 m.get('a'); // 1 5 m.has('a'); // true 6 m.delete('c'); 7 m.clear(); 8 m.keys(); 9 m.values(); 10 m.entries(); 11 m.forEach(function(value, key) { });
11、集合Set
对应C#中的HashSet<object>类型。
1 var set = new Set([1, 2, 3]); 2 set.add(4); 3 set.has(2); 4 set.delete(3); 5 set.clear(); 6 set.size; 7 set.forEach(x => { });
12、Promise
js异步编程,对应C#中的Task<object>。
- then/catch/finally
1 var script = new Script(); 2 script.Context.Langs = new[] { "js" }; 3 var result = script.Eval("await new Promise((resolve, reject) => resolve(1)).then(x => x + 1).catch(err=>{})"); 4 Assert.AreEqual(2L, result);
- Promise.all
1 var s = @" 2 var arr = await Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]); 3 arr[0] + arr[1] + arr[2] 4 "; 5 var script = new Script(); 6 script.Context.Langs = new[] { "js" }; 7 var result = script.Eval(s); 8 Assert.AreEqual(6L, result);
- Promise.any
1 var script = new Script(); 2 script.Context.Langs = new[] { "js" }; 3 var result = script.Eval<long>("await Promise.any([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])"); 4 Assert.AreEqual(1L, result);
13、数学函数
1 Math.abs(-5); // 5 2 Math.acos(0.5); 3 Math.acosh(2); 4 Math.asin(0.5); 5 Math.asinh(2); 6 Math.atan(1); 7 Math.atan2(1, 1); 8 Math.atanh(0.5); 9 Math.tan(0); 10 Math.tanh(0); 11 Math.sign(5); 12 Math.sin(0); 13 Math.sinh(0); 14 Math.cbrt(27); 15 Math.ceil(5.1); 16 Math.clz32(1); 17 Math.cos(0); 18 Math.cosh(0); 19 Math.exp(1); 20 Math.expm1(1); 21 Math.floor(5.9); // 5.0 22 Math.fround(5.5); 23 Math.hypot(3, 4); 24 Math.imul(2, 3); 25 Math.log(1); 26 Math.log10(100); 27 Math.log1p(1); 28 Math.log2(8); 29 Math.max(1, 10, 5); // 10.0 30 Math.min(1, 10, 5); // 1.0 31 Math.pow(2, 3); // 8.0 32 Math.random(); // [0,1) 33 Math.round(5.4); // 5.0 34 Math.sqrt(4); // 2.0 35 Math.pow(3, 2); // 9.0 36 Math.trunc(5.9); // 5.0 37 Math.E; 38 Math.PI; 39 Math.SQRT2; 40 Math.SQRT1_2; 41 Math.LN2; 42 Math.LN10; 43 Math.LOG2E; 44 Math.LOG10E;
14、setTimeout/clearTimeout
1 string code = @" 2 var result = 0; 3 function onTimeout(a, b) { 4 result = a + b; 5 } 6 var handle = setTimeout(onTimeout, 50, 10, 20); 7 handle; 8 "; 9 var script = new Script(); 10 script.Context.Langs = new[] { "js" }; 11 script.Eval<object>(code); 12 Thread.Sleep(100); 13 Assert.AreEqual(30L, script.Eval("result"));
15、setInterval/clearInterval
1 string code = @" 2 var count = 0; 3 function handler() { count = 1; } 4 var timer = setInterval(handler, 40); 5 timer; 6 "; 7 var script = new Script(); 8 script.Context.Langs = new[] { "js" }; 9 var timerObj = script.Eval<object>(code); 10 Thread.Sleep(70); 11 script.Eval("clearInterval(timer)"); 12 Assert.AreEqual(1L, script.Eval("count"));
16、if条件
支持对象检测,null/undefined/0/false/空字符串为false,其他值为true。
1 string code = @" 2 var n = 15; 3 var result = ''; 4 if (n < 10) { 5 result = 'less than 10'; 6 } else if (n < 20) { 7 result = 'less than 20'; 8 } else { 9 result = '20 or more'; 10 } 11 result; 12 "; 13 var script = new Script(); 14 script.Context.Langs = new[] { "js" }; 15 Assert.AreEqual("less than 20", script.Eval(code));
17、for循环
循环中支持 continue/break/return 控制。
1 string code = @" 2 var sum = 0; 3 for (var i = 0; i < 5; i++) { 4 sum += i; 5 } 6 sum; 7 "; 8 var script = new Script(); 9 script.Context.Langs = new[] { "js" }; 10 Assert.AreEqual(10L, script.Eval(code));
18、for of遍历值
循环中支持 continue/break/return 控制。
1 string code = @" 2 var list = ['tom', 'jim', 'john']; 3 var s = ''; 4 for(var item of list) { 5 s += item + ','; 6 } 7 s 8 "; 9 var script = new Script(); 10 script.Context.Langs = new[] { "js" }; 11 Assert.AreEqual("tom,jim,john,", script.Eval(code));
19、for in遍历数组或集合
循环中支持 continue/break/return 控制。
1 string code = @" 2 var list = ['tom', 'jim', 'john']; 3 var s = ''; 4 for(var i in list) { 5 s += list[i] + ','; 6 } 7 s 8 "; 9 var script = new Script(); 10 script.Context.Langs = new[] { "js" }; 11 Assert.AreEqual("tom,jim,john,", script.Eval(code));
20、for in遍历对象或字典
循环中支持 continue/break/return 控制。
1 string code = @" 2 var person = { 'name': 'Bob', age: 25 }; 3 var s = ''; 4 for(var key in person) { 5 s += key + ':' + person[key] + ','; 6 } 7 s 8 "; 9 var script = new Script(); 10 script.Context.Langs = new[] { "js" }; 11 Assert.AreEqual("name:Bob,age:25,", script.Eval(code));
21、while循环
循环中支持 continue/break/return 控制。
1 string code = @" 2 var i = 0; 3 var sum = 0; 4 while (i < 5) { 5 sum += i; 6 i++; 7 } 8 sum; 9 "; 10 var script = new Script(); 11 script.Context.Langs = new[] { "js" }; 12 Assert.AreEqual(10L, script.Eval(code));
22、require引用模块
使用require引用模块并返回模块实例,如: var fs = require(‘fs‘) 。
如果父级上下文环境或者所在语言环境已引用相同模块,则不会重复安装模块,直接返回该模块实例。
四、fs文件模块
注:服务端项目请谨慎添加文件模块,避免脚本中恶意删除、修改文件。
1)安装nuget包
install-package AScript.Lang.JavaScript.fs
2)添加fs模块
JavaScriptLang.Instance.AddModule("fs", new JavaScriptFileSystemModule());
3)同步读写文件
1 string s = @" 2 var fs = require('fs'); 3 fs.writeFileSync('test.txt', 'hello world', 'utf-8'); 4 fs.readFileSync('test.txt', 'utf-8') 5 "; 6 var script = new Script(); 7 script.Context.Langs = new[] { "js" }; 8 var result = script.Eval(s); 9 Assert.AreEqual("hello world", result);
4)异步读写文件
1 string s = @" 2 var fs = require('fs'); 3 await fs.writeFile('test.txt', 'async write', 'utf-8'); 4 await fs.readFile('test.txt', 'utf-8') 5 "; 6 var script = new Script(); 7 script.Context.Langs = new[] { "js" }; 8 var result = await script.EvalAsync<string>(s); 9 Assert.AreEqual("async content", result);
5)其他方法
1 var fs = require('fs'); 2 fs.appendFileSync('test.txt', 'append content', 'utf-8'); // 同步追加文件 3 fs.appendFile('test.txt', 'append context', 'utf-8'); // 异步追加文件 4 fs.copyFileSync('test.txt', 'test_copy.txt'); // 同步拷贝文件 5 fs.copyFile('test.txt', 'test_copy.txt'); // 异步拷贝文件 6 fs.unlinkSync('test.txt'); // 同步删除文件 7 fs.unlink('test.txt'); // 异步删除文件 8 var reader = fs.createReadStream('test.txt'); // 读文件流 9 var writer = fs.createWriteStream('test2.txt'); // 写文件流 10 reader.pipe(writer); // 读取文件流并写入目标文件流 11 // 读文件流事件:open/data/error/end/close 12 reader.on('data', function(chunk) { 13 console.log(chunk); 14 }); 15 reader.on('end', function() { 16 console.log('end'); 17 }); 18 // 写文件流事件:open/error/finish/close 19 writer.on('open', ()=>console.log('open')); 20 writer.on('close', ()=>console.log('close')); 21 writer.write('hello'); 22 writer.end();
五、axios模块
1)安装nuget包
install-package AScript.Lang.JavaScript.axios
2)添加axios模块
JavaScriptLang.Instance.AddModule("axios", new JavaScriptAxiosModule());
3)get
1 string s = @" 2 var axios = require('axios'); 3 await axios.get('http://test.com/api/user/list'); 4 "; 5 var script = new Script(); 6 script.Context.Langs = new[] { "js" }; 7 var result = script.Eval<dynamic>(s); 8 var data = result.data;
4)post
1 string s = @" 2 var axios = require('axios'); 3 await axios.post('http://test.com/api/user/update', {code:'123',name:'tom'}); 4 "; 5 var script = new Script(); 6 script.Context.Langs = new[] { "js" }; 7 var result = script.Eval<dynamic>(s); 8 var data = result.data;
5)其他方法
1 var axios = require('axios'); 2 var instance = axios.create({baseURL:'http://test.com'}); 3 instance.get('/api/user/list') 4 .then(res=>{}) 5 .catch(err=>{}); 6 instance.post('/api/user/update', {code:'123',name:'tom'}) 7 .then(res=>{}) 8 .catch(err=>{}); 9 instance.put('/api/user', {}); 10 instance.delete('/api/user', {}); 11 // mock 12 var mockInstance = axios.createMock([{code:'123',name:'tom'}, {code:'124',name:'john'}]); 13 var resp = await mockInstance.get('http://test.com/api/user/list'); // resp.data: [{code:'123',name:'tom'}, {code:'124',name:'john'}]
六、结束语
C#中执行JavaScript脚本有很多开源库,比如Microsoft.ClearScript、Jint、Jurassic等,大家常用哪个脚本引擎呢?不妨试试AScript.Lang.JavaScript引擎。
AScript开源地址:https://gitee.com/rockey627/AScript
文章摘自:https://www.cnblogs.com/rockey627/p/21601395
