搜尋
首頁web前端js教程HTA版JSMin(省略修饰语若干)基于javascript语言编写_javascript技巧

以前我使用JSMin的时候,都是从http://fmarcia.info/jsmin/这里打开执行页面,然后把自己的代码粘贴过去,再把减肥后的代码复制回文本编辑工具、保存。

久而久之,我发现这样实在是太麻烦了!既然我们是程序员,为何不自己动手把事情变得简单一点呢?

因此我开始了对JSMin进行“友好化”的工作。

而在进行“友好化”工作的过程中,“不出意料”地遇到了一些意想不到的问题,马上我就讲遇到的是哪些问题、最后怎样解决。

不过由于是在一切问题都解决之后才想起来写文的,所以很抱歉,这次是“无图无真相”。



在开始进行讲解之前,我先说明一下这次问题所涉及到的一些技术知识——如果你具有Windows脚本宿主的编程经验,那么这部分你可以跳过;如果你具有ASP的经验,那么这部分可能有一些内容你已经知道了。

Windows Script Host(WSH)即Windows脚本宿主,表现为一些可执行文件(wscript.exe和cscript.exe),它们的功能是在不受Internet安全策略限制的情况下执行用JScript或VBScript编写的任务文件,从而进行一些系统管理工作。值得注意的是,默认情况下Windows中以.js为扩展名的文件都被认为是WSH文件,如果你尝试双击一个.js文件,你可能会发现一些错误提示,或者被杀毒软件拦截。
HTML Application简写为HTA,顾名思义,是“HTML应用程序”——它和Windows脚本宿主一样在相当宽松的安全条件下执行脚本,和Windows脚本宿主不同的地方是HTML应用程序往往具有较好的图形界面。本质上说一个HTA文件其实就是使用了特殊扩展名的HTM文件,如果你不想在制作界面上花费太多的精力,而又正好同时具有HTML和WSH经验,那么使用HTML Application来解决问题是一个相当不错的选择。需要注意的是HTML Application也常被认为是WPF技术的前身,如果你的目标使用环境具有WPF支持(即.NET框架3.0+),那么使用WPF可能更加适合。HTA文件因为易于创作而一度被用于木马下载器,时至今日可能仍有一些杀毒软件粗暴地将HTA文件判断为木马下载器。就像.exe这样的二进制可执行文件一样,一个HTA文件是否有害是由自身设计决定的,而不是被文件类型先天决定。
FileSystemObject,简称FSO,是Windows脚本技术中为了方便脚本进行文件系统操作而提供的组件对象,在ASP编程中也很常见。
WshShell,是WSH运行环境为了方便脚本操作Shell相关物件而提供的组件对象,很多WSH程序都使用了这一对象。
ADODB.Stream,有的时候也被称作“ADO Stream”,是ADO中为了方便操作二进制数据流而提供的组件对象,但也经常被用在数据库以外的地方,例如文件操作。


“只要在文件图标上点点鼠标就可以”这样的功能特性被称作“外壳关联”之类的东西,很多时候大家对外壳关联的认知是“关联到鼠标双击”什么的。但稍微留心一点的人都会发现在点击鼠标右键弹出的快捷选单中,除了默认的指令以外,还有一些其它的像是“编辑”、“打印”之类的指令。

而我们这一次要做的,就是为.js文件增加一个“Minimize”指令,当我们点击这个指令的时候就会启动JSMin给我们的ECMAScript代码减肥。

就在这里,我遇到了第一个问题:

我编写了一个.js文件(实际上是一个WSH任务文件),用它来实现“自动化”地“安装”。

在Windows中为.js文件增添文件关联,需要在HKCR\.js这个注册表项的“默认”值所对应的“JSFile”——HKCR\JSFile项之下的Shell项添加子项,以及从属的名为Command的子项。

在HKCR\JSFile\Shell下面添加了Minimize项并为Command子项设置了“我的hta文件路径 "%1"”值以后,我发现使用这个Minimize指令后会产生一个“不是合法的可执行文件”这样的错误,而如果在前面添加了start指令,又出现了“打开方式”对话框……

看起来在Shell项下面这么投机取巧好像是不行,所以我只好先读取htafile的文件类型设置,然后将它设置到刚才新增加的Minimize指令中,.js文件中是这样写的:

复制代码 代码如下:

view sourceprint?1 var asocCommand = wshShell.RegRead("HKEY_CLASSES_ROOT\\htafile\\Shell\\Open\\Command\\").replace("%1", instPath + "\\" + appExec).replace("%*", '"%1"');

外壳关联的问题刚解决,紧接着就是命令行参数的解析问题:

最初我打算用WSH任务文件作为这个小工具的载体,但马上我发现默认情况下WSH文件缺乏UI支持——VBScript中的InputBox和HTML中的prompt在用JScript编写的WSH任务文件中是不存在的,如果坚持使用WSH就只能通过Windows控制台来获得用户输入。而如果通过控制台来获得用户输入的话,这个工具的标准使用流程就变成了“鼠标点击文件图标——快捷选单——Minimize——键盘输入一个字符”,在一系列鼠标操作(当然,用键盘操作也是可能的)之后突然改用键盘,这好像不太对劲。

因此,我选择了使用HTA这种可以提供丰富界面的文件类型来作为实现这个工具的途径。

而选择了HTA,也就意味着同样要失去WSH“不外传”的一些特性,例如缺少了用于解析命令行参数的“Arguments”对象。

而在我的构思中,应该是可以通过-level参数指定JSMin的代码缩减等级、通过-silent参数来关闭提示信息的。如果不能从命令行中解读出这些参数,这些功能就没有办法实现。

因此我编写了两个函数:

复制代码 代码如下:

//========//========
// parse command-line info
// 在HTA环境中从命令行中解读出被执行的HTA的实际路径和附加的参数
// 此部分代码由NanaLich原创,您可以不经书面许可在任何情况下直接使用。您不应擅自声称您或您的所属机构创作了这些代码,也不应该擅自以NanaLich的名义发布修改版本。
//========//========
function namedOrNot(args) {
var named = {}, not = [], c;
for(var i = 0; i c = args[i];
switch(c.charAt(0)) {
case "-":
case "/":
c = c.substring(1);
if(c.indexOf("=") > 0) {
c = c.split("=");
named[c.shift()] = c.join("=");
} else if(c.indexOf(":") > 0) {
c = c.split(":");
named[c.shift()] = c.join(":");
} else {
// 不能确定一个命名参数是不是也接受附加参数,这是个未解难题
//i++;
named[c] = args[i + 1];
}
break;
default:
not.push(c);
break;
}
}
args.named = named;
args.unnamed = not;
}
function parseArgs(str) {
var a = [], q = false, c = "", $ = "";
function mit() {
if(c)
a.push(c);
}
for(var i = 0; i $ = str.charAt(i);
if($ == '"') {
q = !q;
} else {
if($ == " " && !q) {
mit();
c = "";
} else {
c += $;
}
}
}
mit();
namedOrNot(a);
return a;
}
//========//========

这样,只要将HTA:Application对象的commandLine属性传入这个函数,就可以获得解析之后的命名和不命名参数了。



解决了命令行参数的问题之后,接下来就是文件的编码问题。

在我们实际的Web开发过程中,我们可能因为各种各样的原因使用“非Unicode区域编码”和“Unicode(UTF-16)编码”以外的其它编码格式,例如“Unicode(UTF-16) Big Endian”和“UTF-8”这两种编码方式。

如果我们通过既有的文本编辑工具来复制、粘贴代码,我们只要在保存文件的时候选择编码类型就可以了;但现在我们正在设计一种免去“打开——复制——粘贴——复制——粘贴——保存”这样繁琐的操作步骤的工具,我们就需要在这个工具中设计自动适应编码类型的功能。

很遗憾,在我的测试中FSO和ADODB.Stream都不具备自动识别文本编码的能力,必须另想其它办法——幸好,在HTA中VBScript也是默认支持的,VBScript虽然没有直接对字节组进行操作的功能,但在VBScript中把字节组当作字符串来进行操作仍然可以在一定程度上满足我们的要求。

因此,我编写了下面这个函数:
复制代码 代码如下:

  Function vbDetectFileEncoding(fn)
    Dim Stream, B3
    Set Stream = CreateObject("ADODB.Stream")
    Stream.Type = 1
    Call Stream.Open()
    Call Stream.LoadFromFile(fn)
    B3 = CStr(Stream.Read(3))
   
    Call Stream.Close()
    Set Stream = Nothing
   
    Dim L1
    L1 = Left(B3, 1)
    If (L1 = ChrW(&hFEFF)) Then
      vbDetectFileEncoding = "unicode"
      Exit Function
    Elseif (L1 = ChrW(&hFFFE)) Then
      vbDetectFileEncoding = "unicodeFEFF"
      Exit Function
    Elseif B3 = (ChrB(&hEF) & ChrB(&hBB) & ChrB(&hBF)) Then
      vbDetectFileEncoding = "utf-8"
      Exit Function
    End If
   
   
    vbDetectFileEncoding = defEncoding
  End Function

这个函数根据一个文本文件中可能存在的BOM来推断文件所采用的编码方式。

这里需要注意的一点是:

ADODB.Stream的相关文档中写道Allowed values are typical strings passed over the interface as Internet character set names (for example, "iso-8859-1", "Windows-1252", and so on). For a list of the character set names that are known by a system, see the subkeys of HKEY_CLASSES_ROOT\MIME\Database\Charset in the Windows Registry.,而注册表中和“Unicode Big Endian”(Encoding 1201)相对应的项目是“unicodeFFFE”,从这些信息上推断在ADO Stream中使用“Unicode Big Endian”编码时应该指定Charset属性为“unicodeFFFE”;

这里有一个容易混淆的实施是:BOM字符的Unicode编号是U+FEFF,而“一般的”“Unicode编码”实为“Unicode Little Endian”——BOM字符会被写成“FF FE”这样两个字节,而在“Unicode Big Endian”中才会被写成“FE FF”。

那么到这里,问题就出现了——如果和“unicodeFFFE”正相反的是“unicodeFEFF”的话,我们可以理解这里面的“FEFF”是BOM字符的Unicode编号;但与此同时代表“Unicode Big Endian”的“unicodeFFFE”中的“FFFE”具有什么含义呢?显然这不可能是“一个Unicode编号为U+FFFE的字符”的意思。

而在实践中,我发现无论为Charset属性设置“unicode”还是“unicodeFFFE”,输出的文件都是采用“Unicode (Little Endian)”编码的,这显然和文档所表达的意思不符。

当我再进一步作出尝试的时候,却发现如果希望输出“Unicode Big Endian”编码的文件,Charset属性应该设置为“unicodeFEFF”——我们很容易发现,“FEFF”正好符合BOM字符在文件中的字节顺序;我们同样可以发现为Charset属性设置“unicodeFXFX”时其实就相当于“用FXFX这样的字节顺序来进行编码”的意思,是享受特殊对待的,并不完全符合注册表中所写的样子。

到现在为止,小工具已经可以读写“Unicode”、“Unicode Big Endian”、“UTF-8”和“非Unicode区域编码”这些编码方式的文件了,只是我仍然没想明白为什么文档和注册表中会写着有误或者完全无用的信息……



上面这些问题被一一解决以后,好像就再也没有什么值得研究的问题了。

但是在使用JSMin的过程中,却发现了另一个问题:

有些人(比方说我)主要使用Windows工作,Windows中文本文件的默认行分隔符号是CR LF对。

而JSMin会把所有的CR都替换成LF,这样的话CR LF对就变成了两个LF的“LF LF”对了。

按照JSMin本来的设计,控制字符LF通常都是要被缩减掉的,因此两个连续的LF也不是什么问题;但jsmin.js有一个新增的功能是保留具有一定特征(/*! ... */)的“重要注释”,而如果在这种“重要注释”中存在CR LF对的话,最终会变成无法去除的两个LF控制字符,这可不好。

为了解决这个问题,我对jsmin.js稍微作了一些修改……不过因为JSMin有点超出我的理解能力,我也只能把CR变成空格,不过好在这样做在Windows中也有一些好处(在大部分的Windows版本中,单独的LF控制字符在“记事本”程序中几乎无法观察到,用它分隔的两行文本看起来也像是粘在了一起),就这么凑合用吧……这部分修改我就不单独列出来了。



本文中所提到的一切代码,都可以在这个压缩包中找到。

压缩包内包含三个文件:install.js是注册文件关联的“安装”脚本、jsmin.hta是使用“Minimize”指令时实际运行的“应用程序”、jsmin.js则是我修改以后的jsmin.js。

将三个文件解压至同一个文件夹之后,双击install.js即可安装本工具。如果您重新安装了操作系统,您可能会发现工具仍然遗留在您的个人文件夹中;只要您双击个人文件夹中遗留下来的install.js,您就又可以使用本工具了。

注意:自Windows XP起,较新版本的Windows会为从网络上下载而来的文件设置一个标志,这个标志可能会让HTA文件不能正常执行,如果你在使用的时候碰到了这样的问题,请点击文件属性对话框中的“解除锁定”按钮以去除这个标志。

更新:修改了install.js。现在在64位Windows 7上也可以正确安装了;安装以后也不用手动“解除锁定”了。


秘密在这里:
复制代码 代码如下:

var appsPath = wshShell.ExpandEnvironmentStrings(wshShell.RegRead(regUSF + "Personal")) + "\\Scriptlet";
 
try{
fso.OpenTextFile(instPath + "\\" + appExec + ":Zone.Identifier", 1).Close();
fso.OpenTextFile(instPath + "\\" + appExec + ":Zone.Identifier", 2).Close();
}catch(ex){ }

文件打包下载 文件附一个改名的jse.方便经常开发js的朋友,以免混淆。
因为好多朋友是用的win2003开发,.js文件使用普通文本打开的,不可能以后用js都让运行吧,直接改成install.jse即可运行了,呵呵。
感谢作者发布这么好的东西。作者的blog地址
http://www.cnblogs.com/NanaLich
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器