add
题目描述
实现一个特殊的 add 对象,要求支持属性访问链式调用和数值运算:
add[100] + 1输出101value[200][300] + 100输出701(累加 100+200+300+100)add[100][200][300] - 300输出300(累加 100+200+300-300)
本题考查 Proxy 代理对象 和 Symbol.toPrimitive 的深度应用。
核心知识点
1. Proxy 代理对象
- 基本概念: Proxy 可以拦截并自定义操作(如属性查找、赋值、枚举、函数调用等)
- get 捕获器: 拦截对象的读取属性操作
- 应用场景: 动态属性生成、数据验证、操作记录等
2. Symbol.toPrimitive
- 作用: 对象转换为原始值时调用的方法
- 优先级: 最高,优先于 valueOf() 和 toString()
- 参数: hint 可以是 'number'、'string' 或 'default'
3. 链式调用设计模式
- 核心思想: 每次操作返回新的相同类型对象
- 累积状态: 在对象内部维护累积值
代码实现
javascript
function createProxy(value = 0) {
return new Proxy(
{},
{
get(target, property) {
// 拦截 Symbol.toPrimitive,用于数值转换
if (property === Symbol.toPrimitive) {
return () => value
}
// 累加属性值,返回新的代理对象
return createProxy(value + Number(property))
},
},
)
}
const add = createProxy()
export default add关键技术点
1. Proxy get 捕获器的妙用
javascript
// 捕获器参数详解
get(target, property, receiver) {
// target: 被代理的原始对象
// property: 被访问的属性名(可以是字符串或 Symbol)
// receiver: 代理对象本身
}2. 数值转换的关键点
javascript
// Symbol.toPrimitive 的实现
if (property === Symbol.toPrimitive) {
return () => value; // 返回函数,而不是直接返回值
}3. 类型转换注意事项
javascript
Number('100') // 100 - 正常转换
Number('abc') // NaN - 非数字字符串
Number('') // 0 - 空字符串
Number(null) // 0 - null转换扩展思考
1. 性能优化思路
javascript
// 缓存优化版本
const proxyCache = new Map()
function createProxy(value = 0) {
if (proxyCache.has(value)) {
return proxyCache.get(value)
}
const proxy = new Proxy(
{},
{
get(t, p) {
if (p === Symbol.toPrimitive) {
return () => value
}
return createProxy(value + Number(p))
},
},
)
proxyCache.set(value, proxy)
return proxy
}2. 支持更多操作符
javascript
// 扩展版本支持减法
function createProxy(value = 0) {
return new Proxy(
{},
{
get(t, p) {
if (p === Symbol.toPrimitive) {
return () => value
}
// 支持负数语法 add.sub[100]
if (typeof p === 'string' && p.startsWith('sub')) {
return createProxy(value - Number(p.slice(3)))
}
return createProxy(value + Number(p))
},
},
)
}3. 类型安全版本
javascript
function createProxy(value = 0) {
return new Proxy(
{},
{
get(t, p) {
if (p === Symbol.toPrimitive) {
return () => value
}
const numValue = Number(p)
if (isNaN(numValue)) {
throw new TypeError(`Invalid property: ${String(p)}`)
}
return createProxy(value + numValue)
},
},
)
}