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