一、背景与概念说明
在 Vue 3 的编译阶段中,模板(template)需要被解析成 JavaScript 表达式。例如:
            
            
              css
              
              
            
          
          <div>{{ user.name }}</div>
        会被编译为:
            
            
              vbscript
              
              
            
          
          _createElementVNode("div", null, _toDisplayString(user.name))
        然而,模板中的表达式必须是合法的 JavaScript 语法 ,同时不能包含某些保留关键字(如 for, while, class 等)。
因此,Vue 编译器需要一个安全机制去检测表达式是否合法------这正是 validateBrowserExpression 函数的职责。
二、源码概览
            
            
              vbnet
              
              
            
          
          import type { SimpleExpressionNode } from './ast'
import type { TransformContext } from './transform'
import { ErrorCodes, createCompilerError } from './errors'
// 1️⃣ 定义不允许出现在表达式中的关键字
const prohibitedKeywordRE = new RegExp(
  '\b' +
    (
      'arguments,await,break,case,catch,class,const,continue,debugger,default,' +
      'delete,do,else,export,extends,finally,for,function,if,import,let,new,' +
      'return,super,switch,throw,try,var,void,while,with,yield'
    )
      .split(',')
      .join('\b|\b') +
    '\b',
)
// 2️⃣ 定义用于剔除字符串字面量的正则(防止误匹配)
const stripStringRE =
  /'(?:[^'\]|\.)*'|"(?:[^"\]|\.)*"|`(?:[^`\]|\.)*${|}(?:[^`\]|\.)*`|`(?:[^`\]|\.)*`/g
/**
 * 3️⃣ 表达式验证函数
 * 主要在浏览器端运行时编译器中调用
 */
export function validateBrowserExpression(
  node: SimpleExpressionNode,
  context: TransformContext,
  asParams = false,
  asRawStatements = false,
): void {
  const exp = node.content
  // ① 空表达式情况(例如 v-if="")由上层指令处理
  if (!exp.trim()) {
    return
  }
  try {
    // ② 构造一个 Function 来检测表达式语法是否合法
    new Function(
      asRawStatements
        ? ` ${exp} `
        : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`,
    )
  } catch (e: any) {
    // ③ 捕获语法错误并进一步检查是否包含关键字
    let message = e.message
    const keywordMatch = exp
      .replace(stripStringRE, '')
      .match(prohibitedKeywordRE)
    if (keywordMatch) {
      message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`
    }
    // ④ 通过上下文的 onError 报告错误
    context.onError(
      createCompilerError(
        ErrorCodes.X_INVALID_EXPRESSION,
        node.loc,
        undefined,
        message,
      ),
    )
  }
}
        三、原理解析
1️⃣ 关键逻辑:用 new Function() 检测表达式是否合法
        
            
            
              javascript
              
              
            
          
          new Function(`return (${exp})`)
        这一技巧利用了 JavaScript 引擎本身的语法检查能力。
- 如果表达式语法错误,会直接抛出 
SyntaxError。 - 如果语法合法,则不会报错,说明可安全用于运行时求值。
 
例如:
            
            
              javascript
              
              
            
          
          new Function('return (user.name)')  // ✅ 通过
new Function('return (if)')         // ❌ SyntaxError: Unexpected token 'if'
        2️⃣ 防止关键字误用
Vue 不希望用户写出类似:
            
            
              csharp
              
              
            
          
          <div>{{ class }}</div>
        虽然这是合法的 JS 标识符(在模板上下文中可能被误解析),但会与 JS 关键字冲突。
因此,使用正则 prohibitedKeywordRE 检测关键字出现。
注意这里的关键点:
- 先使用 
stripStringRE去掉字符串字面量,防止"return"这种字符串触发误报。 - 然后再匹配关键字。
 
3️⃣ 错误汇报机制
通过 context.onError 统一抛出编译阶段错误:
            
            
              javascript
              
              
            
          
          context.onError(
  createCompilerError(
    ErrorCodes.X_INVALID_EXPRESSION,
    node.loc,
    undefined,
    message,
  )
)
        这会被编译器统一捕获并转化为编译日志或提示信息。
四、对比分析
| 特性 | validateBrowserExpression | 
Vue 服务器端编译器 (SSR) | Babel 等工具 | 
|---|---|---|---|
| 检查方式 | 运行时 new Function() | 
静态 AST 解析 | 语法树静态分析 | 
| 运行环境 | 浏览器 | Node.js | 通用 | 
| 目的 | 快速语法检测 + 安全关键字过滤 | 静态优化 + 安全执行 | 完整语言解析 | 
| 性能 | 快速、轻量 | 相对较重 | 较慢但最精确 | 
五、实践示例
✅ 合法表达式
            
            
              css
              
              
            
          
          <div>{{ user.age + 1 }}</div>
        验证过程:
exp = "user.age + 1"new Function("return (user.age + 1)")✅ 无异常- 校验通过。
 
❌ 非法表达式(语法错误)
            
            
              css
              
              
            
          
          <div>{{ if user.age }}</div>
        验证过程:
- 抛出 
SyntaxError: Unexpected identifier - 捕获错误 → 报告 
X_INVALID_EXPRESSION。 
⚠️ 关键字误用
            
            
              csharp
              
              
            
          
          <div>{{ class }}</div>
        验证过程:
- 
语法层面
new Function不报错(因为class是保留字) - 
但关键字匹配命中 → 提示:
vbnetavoid using JavaScript keyword as property name: "class" 
六、拓展思考
- 安全性 :
new Function()在编译器中使用是安全的,因为它只执行语法检查,不执行结果。但若在运行时执行用户输入,则会有安全风险。 - 替代方案 :
在更严格的环境中,可以使用 AST 解析器(如@babel/parser)进行安全检测。 - 兼容性 :
某些浏览器中对new Function()的语法报错信息不同,因此 Vue 使用自定义错误代码 (ErrorCodes.X_INVALID_EXPRESSION) 统一处理。 
七、潜在问题与优化方向
| 问题点 | 说明 | 可能优化 | 
|---|---|---|
| 错误定位不精确 | 只能指出哪一条表达式出错,不能指出字符位置 | 可结合 AST 报错精确行列 | 
| 关键字正则维护复杂 | 新的 JS 关键字需手动更新 | 可自动生成关键字列表 | 
| 性能瓶颈 | 大量表达式时多次构造 Function 对象 | 
可在编译时缓存校验结果 | 
八、总结
validateBrowserExpression 是 Vue 编译器的核心安全防线之一,它通过:
new Function()检查表达式语法;- 正则匹配禁止关键字;
 - 报告编译错误;
 
实现了轻量、快速且安全的模板表达式验证。
这一实现方案在运行时编译环境中兼顾了性能与安全性,为 Vue 模板的动态编译提供了强有力的保障。
本文部分内容借助 AI 辅助生成,并由作者整理审核。