Skip to content

proxy和reflect

ts
function delay(f, ms) {
  return new Proxy(f, {
    apply(target, thisArg, args) {
      setTimeout(() => target.apply(thisArg, args), ms)
    },
  })
}

function sayHi(user) {
  console.log(`Hello, ${user}!`)
}

sayHi = delay(sayHi, 3000)

console.log(sayHi.length) // 1 (*) proxy 转发“获取 length” 操作到目标对象

sayHi('John') // Hello, John! (3秒后)
function delay(f, ms) {
  return new Proxy(f, {
    apply(target, thisArg, args) {
      setTimeout(() => target.apply(thisArg, args), ms)
    },
  })
}

function sayHi(user) {
  console.log(`Hello, ${user}!`)
}

sayHi = delay(sayHi, 3000)

console.log(sayHi.length) // 1 (*) proxy 转发“获取 length” 操作到目标对象

sayHi('John') // Hello, John! (3秒后)
ts
function formatNumber(str) {
  let lastStr = str.substring(str.indexOf('.'))
  let formatStr = str.substring(0, str.indexOf('.'))
  // ["0", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
  console.log(lastStr)
  console.log(formatStr)
  let re = formatStr.split('').reverse()
  console.log(re)
  return (
    re.reduce((acc, cur, index) => {
      return (index % 3 ? cur : cur + ',') + acc
    }) + lastStr
  )
}
console.log(formatNumber('1234569234280689.45'))
export {}
function formatNumber(str) {
  let lastStr = str.substring(str.indexOf('.'))
  let formatStr = str.substring(0, str.indexOf('.'))
  // ["0", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
  console.log(lastStr)
  console.log(formatStr)
  let re = formatStr.split('').reverse()
  console.log(re)
  return (
    re.reduce((acc, cur, index) => {
      return (index % 3 ? cur : cur + ',') + acc
    }) + lastStr
  )
}
console.log(formatNumber('1234569234280689.45'))
export {}
ts
const dog = {
  name: `小黄`,
  friends: [
    {
      name: `小红`,
    },
  ],
}

// 1.首先new一个Proxy对象
let proxy = new Proxy(dog, {
  // 2.参数一为需要代理的数据,参数二为上图可以代理的13种的配置对象
  get(target, property) {
    // 3.参数1为上面dog对象,参数2为dog的属性
    console.log(`get被监控到了`)
    return target[property]
  },
  set(target, property, value, obj) {
    // 4.参数1为上面dog对象,参数2为dog的属性,参数3为设置的新值
    // 有点类似Object.defineProperty
    console.log(obj)
    console.log(target, property, value)
    console.log(`set被监控到了`)
    target[property] = value
  },
})

// 那么接下来我们设置一下这个属性
// Dog.name = '小红'  // set值时,发现不会打印 'set被监控到了'
// Dog.name // get值时,发现不会打印 'get被监控到了'

// 思考:为什么在set/get值的时候不会打印出来我们需要的东西呢?

// 上面说得很明白了,proxy相当于是一个壳,代理我们需要监控的数据,也就是我们要通过proxy来访问内部数据才会被监控到

proxy.name = `小红` // 打印输出 'set被监控到了'
console.log(proxy.name)
export {}
const dog = {
  name: `小黄`,
  friends: [
    {
      name: `小红`,
    },
  ],
}

// 1.首先new一个Proxy对象
let proxy = new Proxy(dog, {
  // 2.参数一为需要代理的数据,参数二为上图可以代理的13种的配置对象
  get(target, property) {
    // 3.参数1为上面dog对象,参数2为dog的属性
    console.log(`get被监控到了`)
    return target[property]
  },
  set(target, property, value, obj) {
    // 4.参数1为上面dog对象,参数2为dog的属性,参数3为设置的新值
    // 有点类似Object.defineProperty
    console.log(obj)
    console.log(target, property, value)
    console.log(`set被监控到了`)
    target[property] = value
  },
})

// 那么接下来我们设置一下这个属性
// Dog.name = '小红'  // set值时,发现不会打印 'set被监控到了'
// Dog.name // get值时,发现不会打印 'get被监控到了'

// 思考:为什么在set/get值的时候不会打印出来我们需要的东西呢?

// 上面说得很明白了,proxy相当于是一个壳,代理我们需要监控的数据,也就是我们要通过proxy来访问内部数据才会被监控到

proxy.name = `小红` // 打印输出 'set被监控到了'
console.log(proxy.name)
export {}
ts
let dictionary = {
  Hello: 'Hola',
  Bye: 'Adiós',
}

dictionary = new Proxy(dictionary, {
  get(target, phrase) {
    // 拦截读取属性操作
    if (phrase in target) {
      //如果字典包含该短语
      return target[phrase] // 返回译文
    } else {
      // 否则返回未翻译的短语
      return phrase
    }
  },
})
console.log(dictionary['Hello'])
console.log(dictionary['welcome to beijing'])
export {}
let dictionary = {
  Hello: 'Hola',
  Bye: 'Adiós',
}

dictionary = new Proxy(dictionary, {
  get(target, phrase) {
    // 拦截读取属性操作
    if (phrase in target) {
      //如果字典包含该短语
      return target[phrase] // 返回译文
    } else {
      // 否则返回未翻译的短语
      return phrase
    }
  },
})
console.log(dictionary['Hello'])
console.log(dictionary['welcome to beijing'])
export {}
ts
let numbers = []

numbers = new Proxy(numbers, {
  // (*)
  set(target, prop, val) {
    // 拦截写入操作
    if (typeof val == 'number') {
      target[prop] = val
      return true
    } else {
      return false
    }
  },
})

numbers.push(1) // 添加成功
numbers.push(2) // 添加成功
console.log('Length is: ' + numbers.length) // 2

try {
  numbers.push('test')
} catch (error) {
  console.log('有错误', error)
} // TypeError (proxy 的 `set` 操作返回 false)
let numbers = []

numbers = new Proxy(numbers, {
  // (*)
  set(target, prop, val) {
    // 拦截写入操作
    if (typeof val == 'number') {
      target[prop] = val
      return true
    } else {
      return false
    }
  },
})

numbers.push(1) // 添加成功
numbers.push(2) // 添加成功
console.log('Length is: ' + numbers.length) // 2

try {
  numbers.push('test')
} catch (error) {
  console.log('有错误', error)
} // TypeError (proxy 的 `set` 操作返回 false)
ts
let user = {
  name: 'John',
  age: 30,
  _password: '***',
}

user = new Proxy(user, {
  ownKeys(target) {
    return Object.keys(target).filter((key) => !key.startsWith('_'))
  },
})

// "ownKeys" 过滤掉 _password
for (let key in user) console.log(key) // name,然后是 age

// 对这些方法同样有效:
console.log(Object.keys(user)) // name,age
console.log(Object.values(user)) // John,30
// 我们使用 ownKeys 钩子拦截 for..in 对 user 的遍历,还使用 Object.keys 和 Object.values 来跳过以下划线 _ 开头的属性:
let user = {
  name: 'John',
  age: 30,
  _password: '***',
}

user = new Proxy(user, {
  ownKeys(target) {
    return Object.keys(target).filter((key) => !key.startsWith('_'))
  },
})

// "ownKeys" 过滤掉 _password
for (let key in user) console.log(key) // name,然后是 age

// 对这些方法同样有效:
console.log(Object.keys(user)) // name,age
console.log(Object.values(user)) // John,30
// 我们使用 ownKeys 钩子拦截 for..in 对 user 的遍历,还使用 Object.keys 和 Object.values 来跳过以下划线 _ 开头的属性:
ts
let user = {
  name: 'John',
  _password: '***',
}

user = new Proxy(user, {
  get(target, prop) {
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    }
    let value = target[prop]
    return typeof value === 'function' ? value.bind(target) : value // (*)
  },
  set(target, prop, val) {
    // 拦截写入操作
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    } else {
      target[prop] = val
      return true
    }
  },
  deleteProperty(target, prop) {
    // 拦截属性删除
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    } else {
      delete target[prop]
      return true
    }
  },
  ownKeys(target) {
    // 拦截读取属性列表
    return Object.keys(target).filter((key) => !key.startsWith('_'))
  },
})

// “get” 不允许读取 _password
try {
  console.log(user._password) // Error: Access denied
} catch (e) {
  console.log(e.message)
}

//  “set” 不允许写入 _password
try {
  user._password = 'test' // Error: Access denied
} catch (e) {
  console.log(e.message)
}

// “deleteProperty” 不允许删除 _password 属性
try {
  delete user._password // Error: Access denied
} catch (e) {
  console.log(e.message)
}

// “ownKeys” 过滤排除 _password
for (let key in user) console.log(key) // name
let user = {
  name: 'John',
  _password: '***',
}

user = new Proxy(user, {
  get(target, prop) {
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    }
    let value = target[prop]
    return typeof value === 'function' ? value.bind(target) : value // (*)
  },
  set(target, prop, val) {
    // 拦截写入操作
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    } else {
      target[prop] = val
      return true
    }
  },
  deleteProperty(target, prop) {
    // 拦截属性删除
    if (prop.startsWith('_')) {
      throw new Error('Access denied')
    } else {
      delete target[prop]
      return true
    }
  },
  ownKeys(target) {
    // 拦截读取属性列表
    return Object.keys(target).filter((key) => !key.startsWith('_'))
  },
})

// “get” 不允许读取 _password
try {
  console.log(user._password) // Error: Access denied
} catch (e) {
  console.log(e.message)
}

//  “set” 不允许写入 _password
try {
  user._password = 'test' // Error: Access denied
} catch (e) {
  console.log(e.message)
}

// “deleteProperty” 不允许删除 _password 属性
try {
  delete user._password // Error: Access denied
} catch (e) {
  console.log(e.message)
}

// “ownKeys” 过滤排除 _password
for (let key in user) console.log(key) // name
ts
let range = {
  start: 1,
  end: 10,
}

range = new Proxy(range, {
  has(target, prop) {
    return prop >= target.start && prop <= target.end
  },
})

console.log(5 in range) // true
console.log(50 in range) // false
let range = {
  start: 1,
  end: 10,
}

range = new Proxy(range, {
  has(target, prop) {
    return prop >= target.start && prop <= target.end
  },
})

console.log(5 in range) // true
console.log(50 in range) // false
ts
const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
// 对象键自动转换为字符串;
const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
// 对象键自动转换为字符串;
ts
let user = {
  name: 'John',
}

user = new Proxy(user, {
  get(target, prop, receiver) {
    console.log(`GET ${prop}`)
    return Reflect.get(target, prop, receiver) // (1)
  },
  set(target, prop, val, receiver) {
    console.log(`SET ${prop}=${val}`)
    return Reflect.set(target, prop, val, receiver) // (2)
  },
})
console.log(user)
// console.log(Object.prototype.toString.call(user));
let name = user.name // shows "GET name"
user.name = 'Pete' // shows "SET name=Pete"
let user = {
  name: 'John',
}

user = new Proxy(user, {
  get(target, prop, receiver) {
    console.log(`GET ${prop}`)
    return Reflect.get(target, prop, receiver) // (1)
  },
  set(target, prop, val, receiver) {
    console.log(`SET ${prop}=${val}`)
    return Reflect.set(target, prop, val, receiver) // (2)
  },
})
console.log(user)
// console.log(Object.prototype.toString.call(user));
let name = user.name // shows "GET name"
user.name = 'Pete' // shows "SET name=Pete"

reflect

js
const z = { w: `Super Hello` }
const y = { x: `hello`, __proto__: z }

console.log(Reflect.getOwnPropertyDescriptor(y, `x`))
console.log(Reflect.has(y, `w`))
console.log(Reflect.ownKeys(y, `w`))

console.log(Reflect.has(y, `x`))
console.log(Reflect.deleteProperty(y, `x`))
console.log(Reflect.has(y, `x`))
const z = { w: `Super Hello` }
const y = { x: `hello`, __proto__: z }

console.log(Reflect.getOwnPropertyDescriptor(y, `x`))
console.log(Reflect.has(y, `w`))
console.log(Reflect.ownKeys(y, `w`))

console.log(Reflect.has(y, `x`))
console.log(Reflect.deleteProperty(y, `x`))
console.log(Reflect.has(y, `x`))
js
{
  console.log(`________________________________________________`)
  const obj = new Proxy(
    {},
    {
      get(target, key, receiver) {
        console.log(`getting ${key}!`)
        return Reflect.get(target, key, receiver)
      },
      set(target, key, value, receiver) {
        console.log(`setting ${key}!`)
        return Reflect.set(target, key, value, receiver)
      },
    }
  )
}

{
  console.log(`________________________________________________`)
  const handler = {
    get: (target, name) => (name in target ? target[name] : 29),
  }
  const p = new Proxy({}, handler)
  p.a = 1
  p.b = undefined
  console.log(`c` in p, p.c)
}
{
  console.log(`________________________________________________`)
  const obj = new Proxy(
    {},
    {
      get(target, key, receiver) {
        console.log(`getting ${key}!`)
        return Reflect.get(target, key, receiver)
      },
      set(target, key, value, receiver) {
        console.log(`setting ${key}!`)
        return Reflect.set(target, key, value, receiver)
      },
    }
  )
}

{
  console.log(`________________________________________________`)
  const handler = {
    get: (target, name) => (name in target ? target[name] : 29),
  }
  const p = new Proxy({}, handler)
  p.a = 1
  p.b = undefined
  console.log(`c` in p, p.c)
}

get和set

js
const data = [1, 2, 3]
const p = new Proxy(data, {
  get(target, key, receiver) {
    console.log(`get value:`, key)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log(`set value:`, key, value)
    return Reflect.set(target, key, value, receiver)
  },
})

p.push(1)

// Get value: push
// Get value: length
// Set value: 3 1
// Set value: length 4
const data = [1, 2, 3]
const p = new Proxy(data, {
  get(target, key, receiver) {
    console.log(`get value:`, key)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log(`set value:`, key, value)
    return Reflect.set(target, key, value, receiver)
  },
})

p.push(1)

// Get value: push
// Get value: length
// Set value: 3 1
// Set value: length 4

proxy构造函数

js
class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  say() {
    console.log(`my name is ${this.name}, and my age is ${this.age}`)
  }
}
const proxyTrack = (targetClass) => {
  const prototype = targetClass.prototype
  Object.getOwnPropertyNames(prototype).forEach((name) => {
    targetClass.prototype[name] = new Proxy(prototype[name], {
      apply(target, context, args) {
        console.time()
        target.apply(context, args)
        console.timeEnd()
      },
    })
  })

  return new Proxy(targetClass, {
    construct(target, args) {
      const obj = new target(...args)
      return new Proxy(obj, {
        get(target, prop) {
          console.log(`${target.name}.${prop} is being getting`)
          return target[prop]
        },
      })
    },
  })
}

const MyClass = proxyTrack(Person)
const myClass = new MyClass('tom', 21)
myClass.say()
myClass.name
export {}
class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  say() {
    console.log(`my name is ${this.name}, and my age is ${this.age}`)
  }
}
const proxyTrack = (targetClass) => {
  const prototype = targetClass.prototype
  Object.getOwnPropertyNames(prototype).forEach((name) => {
    targetClass.prototype[name] = new Proxy(prototype[name], {
      apply(target, context, args) {
        console.time()
        target.apply(context, args)
        console.timeEnd()
      },
    })
  })

  return new Proxy(targetClass, {
    construct(target, args) {
      const obj = new target(...args)
      return new Proxy(obj, {
        get(target, prop) {
          console.log(`${target.name}.${prop} is being getting`)
          return target[prop]
        },
      })
    },
  })
}

const MyClass = proxyTrack(Person)
const myClass = new MyClass('tom', 21)
myClass.say()
myClass.name
export {}

proxy校验

js
// 验证规则
const validators = {
  name: {
    validate(value) {
      return value.length > 6
    },
    message: '用户名长度不能小于六',
  },
  password: {
    validate(value) {
      return value.length > 10
    },
    message: '密码长度不能小于十',
  },
  moblie: {
    validate(value) {
      return /^1(3|5|7|8|9)[0-9]{9}$/.test(value)
    },
    message: '手机号格式错误',
  },
}
// 验证方法
function validator(obj, validators) {
  return new Proxy(obj, {
    set(target, key, value) {
      const validator = validators[key]
      if (!validator) {
        target[key] = value
      } else if (validator.validate(value)) {
        target[key] = value
      } else {
        alert(validator.message || '')
      }
    },
  })
}
let form = {}
form = validator(form, validators)
form.name = '666' // 用户名长度不能小于六
form.password = '113123123123123'
// 验证规则
const validators = {
  name: {
    validate(value) {
      return value.length > 6
    },
    message: '用户名长度不能小于六',
  },
  password: {
    validate(value) {
      return value.length > 10
    },
    message: '密码长度不能小于十',
  },
  moblie: {
    validate(value) {
      return /^1(3|5|7|8|9)[0-9]{9}$/.test(value)
    },
    message: '手机号格式错误',
  },
}
// 验证方法
function validator(obj, validators) {
  return new Proxy(obj, {
    set(target, key, value) {
      const validator = validators[key]
      if (!validator) {
        target[key] = value
      } else if (validator.validate(value)) {
        target[key] = value
      } else {
        alert(validator.message || '')
      }
    },
  })
}
let form = {}
form = validator(form, validators)
form.name = '666' // 用户名长度不能小于六
form.password = '113123123123123'

array push

js
const handle = (params) => {
  if (Array.isArray(params)) {
    return params.reduce((accumulator, currentValue) => {
      typeof currentValue === 'object'
        ? accumulator.push(handle(currentValue))
        : accumulator.push(currentValue)
      return accumulator
    }, [])
  } else {
    return Reflect.ownKeys(params).reduce((accumulator, currentValue) => {
      typeof params[currentValue] === 'object'
        ? (accumulator[currentValue] = handle(params[currentValue]))
        : (accumulator[currentValue] = params[currentValue])
      return accumulator
    }, {})
  }
}

let a = [
  {
    age: '23',
    name: 334,
  },
  { time: 'ee', date: new Date() },
]
b = handle(a)
b.push({ naa: 'erer' })
console.log(b)
console.log(a)
export {}
const handle = (params) => {
  if (Array.isArray(params)) {
    return params.reduce((accumulator, currentValue) => {
      typeof currentValue === 'object'
        ? accumulator.push(handle(currentValue))
        : accumulator.push(currentValue)
      return accumulator
    }, [])
  } else {
    return Reflect.ownKeys(params).reduce((accumulator, currentValue) => {
      typeof params[currentValue] === 'object'
        ? (accumulator[currentValue] = handle(params[currentValue]))
        : (accumulator[currentValue] = params[currentValue])
      return accumulator
    }, {})
  }
}

let a = [
  {
    age: '23',
    name: 334,
  },
  { time: 'ee', date: new Date() },
]
b = handle(a)
b.push({ naa: 'erer' })
console.log(b)
console.log(a)
export {}
js
function extend(sup, base) {
  let descriptor = Object.getOwnPropertyDescriptor(
    base.prototype,
    'constructor'
  )
  base.prototype = Object.create(sup.prototype)
  const handler = {
    construct(target, args) {
      let obj = Object.create(base.prototype)
      this.apply(target, obj, args)
      return obj
    },
    apply(target, that, args) {
      sup.apply(that, args)
      base.apply(that, args)
    },
  }
  let proxy = new Proxy(base, handler)
  descriptor.value = proxy
  Object.defineProperty(base.prototype, 'constructor', descriptor)
  return proxy
}

let Person = function (name) {
  this.name = name
}

let Boy = extend(Person, function (name, age) {
  this.age = age
})

Boy.prototype.sex = 'M'

let Peter = new Boy('Peter', 13)
console.log(Peter.sex) // "M"
console.log(Peter.name) // "Peter"
console.log(Peter.age) // 13
function extend(sup, base) {
  let descriptor = Object.getOwnPropertyDescriptor(
    base.prototype,
    'constructor'
  )
  base.prototype = Object.create(sup.prototype)
  const handler = {
    construct(target, args) {
      let obj = Object.create(base.prototype)
      this.apply(target, obj, args)
      return obj
    },
    apply(target, that, args) {
      sup.apply(that, args)
      base.apply(that, args)
    },
  }
  let proxy = new Proxy(base, handler)
  descriptor.value = proxy
  Object.defineProperty(base.prototype, 'constructor', descriptor)
  return proxy
}

let Person = function (name) {
  this.name = name
}

let Boy = extend(Person, function (name, age) {
  this.age = age
})

Boy.prototype.sex = 'M'

let Peter = new Boy('Peter', 13)
console.log(Peter.sex) // "M"
console.log(Peter.name) // "Peter"
console.log(Peter.age) // 13

Released under the MIT License.