在 ASP.NET (JScript.NET) 頁面中使用 eval() 動態定義變數,在舊版 JScript (Classic ASP) 可行,但在 JScript.NET 「快速模式」下會失敗。本文解析根本原因、快速模式限制,並提供三種解決方案:物件屬性動態擴充、expando 物件、關閉快速模式 (不建議)。
<%@ Page Language="JScript" %>
<script runat="server">
eval("var f1=1, f2=2, f3=3;");
Response.Write(f1 + "<br/>"); // 編譯錯誤:'f1' 未定義
</script>
錯誤訊息:JS1008: 'f1' is not declared 或 eval 方法不能在封閉範圍內定義標識符。
ASP.NET 預設以 快速模式 編譯 JScript.NET,限制包括:
eval() 在「受限安全上下文」執行,且 無法在封閉範圍建立新識別符 (變數/函數)。eval 內定義的變數僅在該次呼叫存活,呼叫結束即銷毀。expando 屬性 (動態新增屬性)。參考:MSDN: 升級先前的 JScript 版本中建立的應用程式
<%@ Page Language="JScript" %>
<script runat="server">
// 建立一個空物件作為容器
var T = new Object();
// 動態新增屬性 (相當於變數)
T.F1 = 1;
T.F2 = 2;
T.F3 = 3;
// 存取
Response.Write("F1 = " + T.F1 + "<br/>");
Response.Write("F2 = " + T.F2 + "<br/>");
Response.Write("F3 = " + T.F3 + "<br/>");
// 迴圈動態產生大量欄位
for (var i = 0; i < 12; i++) {
var key = "F" + i.toString().padStart(3, '0'); // F000, F001...
T[key] = i + 1000;
}
for (var i = 0; i < 12; i++) {
var key = "F" + i.toString().padStart(3, '0');
Response.Write(T[key] + "<br/>");
}
</script>
優點:符合快速模式規則、IntelliSense 友善、可序列化為 JSON、無安全性風險。
<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Dynamic" %>
<script runat="server">
dynamic bag = new System.Dynamic.ExpandoObject();
bag.F1 = 1;
bag.F2 = 2;
bag.DynamicMethod = new Func<string>(() => "Hello");
Response.Write(bag.F1 + " " + bag.DynamicMethod());
</script>
// 命令列編譯器
jsc.exe /fast- MyScript.js
// 或在 web.config (僅理論上,ASP.NET 執行階段強制快速模式)
<system.web>
<compilation debug="true">
<compilers>
<compiler language="JScript" extension=".js" type="Microsoft.JScript.JScriptCodeProvider, Microsoft.JScript, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" compilerOptions="/fast-" />
</compilers>
</compilation>
</system.web>
警告:ASP.NET 執行階段為穩定性強制啟用快速模式,compilerOptions="/fast-" 在 ASP.NET 中不生效,且會導致效能下降、執行緒安全問題。
<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
// 模擬從 DB 取得欄位名稱
string[] fields = { "UserId", "UserName", "Email", "CreateDate" };
// 使用 Dictionary 做強型別容器
var record = new System.Collections.Generic.Dictionary<string, object>();
// 填充資料 (實際從 DataReader 讀取)
record["UserId"] = 1001;
record["UserName"] = "Admin";
record["Email"] = "admin@example.com";
record["CreateDate"] = DateTime.Now;
// 輸出
foreach (var kv in record)
Response.Write($"{kv.Key} = {kv.Value}<br/>");
</script>
<%@ Language=JScript %> 改為 C#,將 eval 邏輯重構為物件操作。