vue2初体验(六):模版表达式全局对象白名单+黑名单(全)

64 阅读5分钟

一. vue模版表达式全局对象白名单

Vue 模板表达式中可用的 JavaScript 全局对象和方法列表

1. Array 对象(完整方法集)

// 基础操作
{{ [1,2,3].concat([4,5]) }}       // [1,2,3,4,5]
{{ [1,2,3].join('-') }}           // "1-2-3"
{{ [1,2,3].slice(1) }}            // [2,3] 
{{ [3,1,2].sort() }}              // [1,2,3]
{{ [1,2,3].reverse() }}           // [3,2,1]

// ES6+ 方法
{{ [1,2,3].includes(2) }}         // true
{{ [1,2,3].find(x => x > 1) }}    // 2
{{ [1,2,3].findIndex(x => x > 1) }} // 1
{{ [1,2,3].indexOf(2) }}          // 1

// 迭代方法
{{ [1,2,3].map(x => x * 2) }}     // [2,4,6]
{{ [1,2,3].filter(x => x > 1) }}  // [2,3]
{{ [1,2,3].reduce((a,b) => a + b) }} // 6
{{ [1,2,3].every(x => x < 5) }}   // true
{{ [1,2,3].some(x => x > 2) }}    // true

// 类型转换
{{ Array.from('foo') }}           // ['f','o','o']
{{ Array.of(1,2,3) }}             // [1,2,3]

2. String 对象(完整方法集)

// 基础操作
{{ 'hello'.toUpperCase() }}        // "HELLO"
{{ 'HELLO'.toLowerCase() }}       // "hello"
{{ '  text  '.trim() }}           // "text"
{{ '  text  '.trimStart() }}      // "text  "
{{ '  text  '.trimEnd() }}        // "  text"

// 子字符串操作
{{ 'hello'.substring(1,3) }}      // "el"
{{ 'hello'.substr(1,3) }}         // "ell" (已废弃,建议用 substring)
{{ 'hello'.slice(1,3) }}          // "el"
{{ 'hello'.charAt(1) }}           // "e"
{{ 'hello'[1] }}                  // "e" (现代写法)

// 搜索与匹配
{{ 'hello'.includes('ell') }}     // true
{{ 'hello'.startsWith('he') }}    // true
{{ 'hello'.endsWith('lo') }}      // true
{{ 'hello'.indexOf('l') }}        // 2
{{ 'hello'.lastIndexOf('l') }}    // 3
{{ 'hello'.match(/l/g) }}         // ["l","l"]

// 分割与替换
{{ 'a,b,c'.split(',') }}          // ["a","b","c"]
{{ 'hello'.replace('l','x') }}    // "hexlo"
{{ 'hello'.replaceAll('l','x') }} // "hexxo"

// 填充与重复
{{ 'hi'.padStart(5,'!') }}        // "!!!hi"
{{ 'hi'.padEnd(5,'!') }}          // "hi!!!"
{{ 'hi'.repeat(3) }}              // "hihihi"

// Unicode 操作
{{ '𠮷'.codePointAt(0) }}         // 134071 (ES6)
{{ String.fromCodePoint(9731) }}  // "☃"

3. 补充其他重要全局对象方法

Object 增强方法

// 属性操作
{{ Object.getOwnPropertyNames({a:1}) }} // ["a"]
{{ Object.hasOwn({a:1}, 'a') }}        // true (ES2022)

// 合并与复制
{{ Object.assign({a:1},{b:2}) }}       // {a:1,b:2}
{{ structuredClone({a:1}) }}          // 深拷贝 (ES2022)

Number 新增方法

{{ Number.isNaN(NaN) }}                // true (比全局 isNaN 更安全)
{{ Number.isSafeInteger(9007199254740991) }} // true
{{ 123.456.toFixed(2) }}               // "123.46"

Math 新增方法

{{ Math.trunc(3.14) }}                 // 3 (去小数)
{{ Math.sign(-5) }}                    // -1
{{ Math.cbrt(8) }}                     // 2 (立方根)
{{ Math.hypot(3,4) }}                  // 5 (勾股定理)

Date 增强方法

{{ new Date().toLocaleString('zh-CN') }} // "2023/7/15 14:30:00"
{{ Date.now() }}                        // 时间戳 (毫秒)

4. 现代集合类型

Map/Set 完整 API

// Map
{{ [...new Map([['key','value']]).entries()] }} // [["key","value"]]
{{ new Map().set('a',1).get('a') }}           // 1

// Set
{{ new Set([1,1,2]).size }}                   // 2
{{ [...new Set([1,2,2])] }}                   // [1,2]

TypedArray 系列

{{ new Uint8Array([1,2,3]).join(',') }}       // "1,2,3"

5. 国际化的 Intl 对象

// 日期格式化
{{ new Intl.DateTimeFormat('zh-CN', { dateStyle: 'full' }).format(new Date()) }}
// 输出示例: "2023年7月15日星期六"

// 数字格式化
{{ new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(1234.5) }}
// 输出示例: "1.234,50 €"

// 列表格式化
{{ new Intl.ListFormat('zh-CN').format(['苹果', '香蕉']) }}
// 输出: "苹果和香蕉"

最佳实践建议

  1. 复杂逻辑处理

    // 不推荐在模板中直接操作
    {{ arr.filter(x => x > 1).map(x => x * 2) }}
    
    // 推荐使用计算属性
    computed: {
      processedData() {
        return this.arr.filter(x => x > 1).map(x => x * 2)
      }
    }
    
  2. 性能敏感操作

    // 避免在模板中频繁创建新对象
    {{ new Intl.DateTimeFormat('zh-CN').format(date) }}
    
    // 推荐预先格式化
    data() {
      return {
        formattedDate: new Intl.DateTimeFormat('zh-CN').format(new Date())
      }
    }
    
  3. 类型安全

    // 使用 Number 的安全检查方法
    {{ Number.isInteger(value) }}  // 优于 {{ value % 1 === 0 }}
    

所有示例均基于最新的 ECMAScript 2023 标准,在 Vue 3 的模板中可直接使用。对于旧版浏览器不支持的现代方法(如 replaceAll),建议通过 Babel 或 polyfill 提供支持。

二. vue模版表达式全局对象黑名单

在 Vue 模板表达式中,不可用的方法主要包括以下几类(按技术栈分类,基于 Vue 3 最新规范):

1. 会修改原数据的数组方法(变异方法)

// ❌ 禁止在模板中直接使用(会触发警告且可能导致渲染问题)
{{ arr.push(1) }}       // 修改原数组
{{ arr.pop() }}         // 修改原数组  
{{ arr.shift() }}       // 修改原数组
{{ arr.unshift(1) }}    // 修改原数组
{{ arr.splice(0,1) }}   // 修改原数组
{{ arr.sort() }}        // 原地排序
{{ arr.reverse() }}     // 原地反转
{{ arr.fill(0) }}       // 原地填充
{{ arr.copyWithin() }}  // 原地操作

2. 会产生副作用的操作

// ❌ 禁止在模板中使用(违反纯函数原则)
{{ alert('test') }}              // 浏览器弹窗
{{ console.log('test') }}        // 控制台输出
{{ window.open() }}              // 新窗口
{{ document.write() }}           // DOM 写入
{{ fetch('/api') }}              // 网络请求
{{ new Promise() }}              // 异步操作
{{ setTimeout() }}               // 定时器
{{ setInterval() }}              // 循环定时器
{{ localStorage.setItem() }}     // 存储操作
{{ sessionStorage.clear() }}     // 存储操作
{{ crypto.getRandomValues() }}   // 加密操作

3. 受限的全局对象访问

// ❌ 以下全局对象默认不可访问(需通过 app.config.globalProperties 手动注入)
{{ window.location.reload() }}    // 浏览器对象
{{ document.getElementById() }}  // DOM 操作
{{ process.env }}                // Node.js 环境变量
{{ require('module') }}          // CommonJS 导入
{{ __dirname }}                  // Node.js 路径
{{ XMLHttpRequest }}             // 直接 AJAX 对象

4. 其他禁止操作

// ❌ 危险或无效操作
{{ delete obj.property }}        // delete 操作符
{{ (() => { throw Error() })() }} // 抛出异常
{{ new Function('return 1')() }} // 动态执行
{{ eval('1+1') }}               // eval 执行
{{ 123 instanceof Number }}      // 原型链操作
{{ this.$router.push() }}        // 路由跳转(应放在方法中)
{{ $emit('event') }}             // 事件触发(模板中仅支持监听)

5. 隐式禁止的 Vue 特殊操作

// ❌ 这些在模板中不会报错但会产生问题
{{ v-if="false" }}              // 指令错误写法(应不带引号)
{{ var x = 1 }}                 // 变量声明(模板中无效)
{{ function test(){} }}         // 函数声明(模板中无效)
{{ import('module') }}          // 动态导入(应放在 script 中)
{{ v-for="(item, index) in items" :key="index" }} // 不推荐的 key 用法

最佳实践对比表

禁止操作替代方案原因
arr.push(1)computed: { newArr() { return [...arr, 1] } }保持数据不可变
alert('hi')methods: { showAlert() { alert('hi') } }副作用隔离
window.location.href通过 app.config.globalProperties 注入后使用安全限制
delete obj.prop{ ...obj, prop: undefined }响应式系统要求

技术栈说明

  1. Vue 3 响应式原理:基于 Proxy 的响应式系统会检测到数组变异方法并抛出警告
  2. 模板编译限制:Vue 模板编译器会静态分析表达式,阻止危险全局访问
  3. 最新规范:所有示例基于 Vue 3.4+ 和 ES2023 标准

如果需要使用受限功能,应通过以下方式:

// 安全的使用方式举例
export default {
  methods: {
    safeArrayUpdate() {
      // 在方法中使用数组变异方法
      this.$set(this.arr, this.arr.push(1))
    },
    safeGlobalAccess() {
      // 在方法中访问 window
      console.log(window.innerWidth)
    }
  }
}