Hanjst汉吉斯特模版语言及模版引擎,近期持续改进升级。
这次改进主要是增加了对安全输出表达式兼容,由于涉及到对软件开发过程中的效率和软件运行效率的平衡和取舍,所以多写了几句,以描述这个权衡利弊对思考过程。距离上次更新:🙋Hanjst汉吉斯特升级:+showImageAsync及性能改进等 ( https://ufqi.com/blog/hanjst-showimage-dotpos/ ),时间过得并不算长,希望Hanjst早日成熟而稳定下来。
1. 问题及背景
Hanjst 模版语言解析引擎在编写时,启用了JavaScript的 strict mode ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode ),对程序语句执行严格对语法检查,因此如果书写不严格会偶尔抛出异常错误警告来。之所以这么要求,使用JavaScript对strict mode,是希望Hanjst汉吉斯特能够用在一些关键领域和苛刻岗位,将异常错误消灭在程序编写阶段。
让异常在“编译时”发生,进而得到解决,属于编程语言方面对准编译型。这本是好事,因为Hanjst 除了用在普通的资讯网站,也会用在电商、金融等领域,对其进行苛刻对语法检查,是必需的步骤。
然而,这也有弊端,就是开发时比较耗费时间,需要考虑各种情况,反复测试各种情景下的软件行为,无意会加大开发成本。比如常见的 strict mode下的报错:未定义变量和访问对象为undefined。报错信息在 Hanjst里有较人性化的显示输出,参考:汉吉斯特Hanjst+更新升级:error reporting, innerLoop和loadingLayer ,https://ufqi.com/blog/hanjst-error-reporting-innerloop-and-loadinglayer/ 。
如果因为对接的系统处于非关键领域和苛刻岗位,对于往复出现的这种变量未定义或者访问undefined对象,能不能进行一些主动兼容?这次就是考察这个问题。
2. 解决思路及方法
对这个问题的考察,大致两种方法:1)在模版编译时,去掉 JavaScript对strict mode,使之不再做严格对检查,从而避免类似未定义变量和访问undefined对象;2)第二种思路是在保持 strict mode对前提下,做一些局部的微调,使之能够兼容这些低级错误,也保留对其他语法对严格检查。
在大的方向上去掉Strict mode显然是不行的,这会从本质上动摇Hanjst用在关键领域和苛刻岗位的定位。这一点不应拿来讨论。启用strict mode,进行编译时语法检查,对严肃软件是必需的。
在JavaScript中,探测一个变量是否被定义,是一件容易的事,使用类似 typeof 对指令,可以判断某个变量是否被定义。如果对每一个变量在输出前都做这样的检查,显然陷入了“一个人有病,全国人吃药💊”的非理智状态,这也是之前的尝试被阻止的原因之一。
因此如果要启用针对变量的探测,需要有某种机制来感知已经被定义了的变量。
另外,如果不使用 JavaScript eval等危险性较高对函数,如何去感知某个字符串所代表对变量是否被定义了?使用内置对象 Function构建匿名函数吗?如果匿名函数的话,其单独的变量作用域与变量实际运行环境又有显著的不同,该如何操作?
第三,在模版语言中,我们允许对象的属性访问,这类对象,可能是运行时环境的全局变量,也可能是局部变量;这类对象既可能是一维的Hash数据list,还可能还多位的Hash嵌套,可能存在第一维的数据对象是已经被定义的,而第二维、第三维是未定义的,而此时如果是未定义的,就有可能抛出异常来。
待问题进一步地发散为:
1)继续启用Strict mode,
2)在1)的情况下,实现对未定义变量和未定义对象对访问兼容;
3)尽量不要使用高危函数,如 eval;
4)保证2)都情况下,不能不分情况的对所有变量进行兼容操作;
5)需要区分是全局变量,还是局部变量,各种情况最好都能兼容;
6)需要区分一维对象和多维对象,各种情况最好都能兼容。
经过一番艰难地探索,在尝试寻求鱼和熊掌兼得的情况下,采取如下措施:
1)使用 typeof 生成待执行的变量是否被定义的JavaScript语句;
2)新增环境变量赋值语句的list,用以检测某个变量是否显式地被定义;
3)使用 window.hasOwnProperty 探测某个全局变量是否被定义;
4)使用递归方式拆解多维数据对象,如, $aList[$ak1][$ak2][$ak3] .
基于以上分析在 Hanjst.js 中新增 _enSafeExpression 函数用于对待输出对变量及对象进行安全性检查。
3. 样例演示
{$a=1} –> 类似的语句被登记为该变量已经被显式地声明;
{$a} –> ((typeof $a == ‘undefined’) ? ” : $a) , 输出 $a 对语句如果探测到没有被定义,将被改写为三目运算符的表达式;
$aList[$ak1][$ak2][$ak3] –> $aList[$ak1], $aList[$ak1][$ak2] , 将待输出对三维数据分别逐级拆解,形成待探测的两个变量/对象,再分别予以构建使用三目运算符的表达式,形成由顶部到底部的逐层检测,大致为:
((typeof $aList[$ak1] == ‘undefined’) ? ” : ((typeof $aList[$ak1][$ak2] == ‘undefined’) ? ” :$aList[$ak1][$ak2][$ak3]))
更多维的数据对象,也依此类推。
4. 其他
版本号升至 v1.7, +其他一些细微的优化调整,
一个简单地问题细究起来,居然一点都不简单,纸上得来终觉浅,绝知此事要躬行。一个小任务,变量输出前进行主动安全性检查,居然唠唠叨叨地写了差不多2000字。
毕竟,Hanjst汉吉斯特在追求平衡的艺术,追求极致而完美。
….
🙋Hanjst汉吉斯特 是一种基于JavaScript的模板语言及模版解析引擎,她运行在客户端或服务器端。
🙋Hanjst汉吉斯特 能够表述逻辑控制,能够实现与服务器端模版语言相同的强大功能。
-
Hanjst当完全在客户端解析时,节省服务器端计算资源;
-
Hanjst模板语言独立,不与服务器端资源做任何绑定;
-
纯粹的MVC,层间数据用JSON格式传递;
-
常见模板语言功能全支持,附带复杂而强大的JavaScript编程能力;
-
无学习成本,直接使用JavaScript书写模板语言;
-
….
Hanjst is a JavaScript-based templating language and parsing engine that runs on both the client-side and/or server-side.
Hanjst can express logical controls and achieve the same functionalities as the server-side templating languages.
-
Hanjst’s Run-time in client-side, reduce computing render in server-side;
-
Hanjst is Language-independent, not-bound with back-end scripts or languages;
-
Totally-isolated between MVC, data transfer with JSON;
-
Full-support template tags with built-in logic and customized JavaScript functions;
-
No more tags languages to be learned, just JavaScript;
-
….
两天来,连续创作两篇,在写blog的历史上,也是少有的行为。同期写就的另一篇: 写写🏦存款利率贷款利率和负利率 , https://ufqi.com/blog/captial-rate-and-minus-rate/ 。
http://ufqi.com/blog/hanjst-ensafeexpr-updt/
-R/x12SX
https://ufqi.com/news/list.932.html