当前位置: 首页 > 工具软件 > Object-proxy > 使用案例 >

proxy与object

薄腾
2023-12-01
const handler = {
  defineProperty(target, prop, descriptor) {
    console.log('trigger defineProperty')
    return Reflect.defineProperty(target, prop, descriptor)
  },
  deleteProperty(target, prop) {
    console.log('trigger deleteProperty')
    return Reflect.deleteProperty(target, prop)
  },
  set(target, prop, value, receiver) {
    console.log('trigger setter & prop => ', prop)
    return Reflect.get(target, prop, value, receiver)
  },
  get(target, prop, receiver) {
    console.log('trigger getter & prop => ',  prop)
    return Reflect.get(target, prop, receiver)
  },
  has(target, prop) {
    console.log('trigger has')
    return Reflect.has(target, prop)
  },
  ownKeys(target) {
    console.log('trigger ownKeys')
    return Reflect.ownKeys(target)
  },
  getOwnPropertyDescriptor(target, prop) {
    console.log('trigger getOwnPropertyDescriptor & prop => ', prop)
    return Reflect.getOwnPropertyDescriptor(target, prop)
  },

  setPrototypeOf(target, prototype) {
    console.log('trigger setPrototypeOf')
    return Reflect.setPrototypeOf(target, prototype)
  },
  getPrototypeOf(target) {
    console.log('trigger getPrototypeOf')
    return Reflect.getPrototypeOf(target)
  },

  preventExtensions(target) {
    console.log('trigger preventExtensions')
    return Reflect.preventExtensions(target)
  },
  isExtensible(target) {
    console.log('trigger isExtensible')
    return Reflect.isExtensible(target)
  },

  apply(target, thisArg, argumentsList) {
    console.log('trigger apply')
    return Reflect.apply(target, thisArg, argumentsList)
  },
  construct(target, argumentsList, newTarget) {
    // console.log(newTarget === proxy)
    console.log('trigger construct')
    return Reflect.construct(target, argumentsList, newTarget)
  }
}

Object 属性与方法

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

Proxy 处理程序

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/construct

属性

Object.prototype.constructor

const foo = function() {
  return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.constructor)

// trigger getter & prop =>  constructor
// [Function: Function]

方法

Object.assign()

const prototype = { num: 11 }
const foo = Object.create(prototype)
foo.id = 'foo'
const symbol = Symbol(foo)
Object.defineProperties(foo, {
  'age': {
    value: 19,
    enumerable: false,
    configurable: true,
    writable: true
  },
  'sex': {
    get: function() {
      return 'man'
    },
    set() {},
    enumerable: true,
    configurable: true
  },
  [symbol]: {
    value: 'symbol-value',
    writable: true,
    enumerable: true,
    configurable: true
  }
})

const proxy = new Proxy(foo, handler)
Object.assign({}, proxy)

打印过程

trigger ownKeys
trigger getOwnPropertyDescriptor & prop =>  id
trigger getter & prop =>  id
trigger getOwnPropertyDescriptor & prop =>  age
trigger getOwnPropertyDescriptor & prop =>  sex
trigger getter & prop =>  sex
trigger getOwnPropertyDescriptor & prop =>  Symbol([object Object])
trigger getter & prop =>  Symbol([object Object])

遍历proxy 对象自身属性,先访问对象属性描述符,可枚举的字符串属性或Symbol属性,访问getter, 设置到目标对象

const proxy = new Proxy(foo, handler)
const proxy2 = new Proxy({}, handler)
Object.assign(proxy2, proxy)
// TypeError: 'set' on proxy: trap returned falsish for property 'id'

目标对象不可以是proxy实例,被合并的源对象可以是proxy

合并过程会触发源proxy对象的捕获器,返回目标对象后对其操作与proxy对象无关

Object.create()

const proxy = new Proxy(foo, handler)
const obj= Object.create(proxy)

设置新对象prototype过程不会触发拦截器
console.log(obj)
访问新对象过程,浏览器与nodejs 表现不同 下面是nodejs中打印结果
trigger getter & prop => Symbol(nodejs.util.inspect.custom)
trigger getOwnPropertyDescriptor & prop => constructor
trigger getPrototypeOf
trigger getPrototypeOf
trigger getter & prop => Symbol(Symbol.toStringTag)
trigger getter & prop => Symbol(Symbol.iterator)
{}
console.log(obj.age)
trigger getter & prop => age
19

Object.defineProperty()

const proxy = new Proxy(foo, handler)
Object.defineProperty(proxy, 'name', {
  value: 'name-value',
  enumerable: true
})
// trigger defineProperty

console.log(proxy)
// 不会触发捕获器

Object.defineProperties()

const proxy = new Proxy(foo, handler)
Object.defineProperties(proxy, {
  'name': {
    value: 'name-value',
    enumerable: true
  },
  'name2': {
    value: 'name2-value',
    enumerable: true
  }
})

// trigger defineProperty
// trigger defineProperty

Object.entries()

const proxy = new Proxy(foo, handler)
Object.entries(proxy)

trigger ownKeys
trigger getOwnPropertyDescriptor & prop =>  id
trigger getter & prop =>  id
trigger getOwnPropertyDescriptor & prop =>  age
trigger getOwnPropertyDescriptor & prop =>  sex
trigger getter & prop =>  sex

没有symbol属性,访问自身 可枚举属性
便于对象 转 map
const map = new Map(Object.entries(object))

Object.fromEntries()

能根据**键值对列表 ** 生成对象
不会触发捕获器
便于map 结构转对象
const obj = Object.fromEntries(map)

Object.getOwnPropertyDescriptor()

const proxy = new Proxy(foo, handler)
Object.getOwnPropertyDescriptor(proxy, 'age')

// trigger getOwnPropertyDescriptor & prop =>  age

Object.getOwnPropertyDescriptors()

const proxy = new Proxy(foo, handler)
console.log(Object.getOwnPropertyDescriptors(proxy))

// trigger ownKeys
// trigger getOwnPropertyDescriptor & prop =>  id
// trigger getOwnPropertyDescriptor & prop =>  age
// trigger getOwnPropertyDescriptor & prop =>  sex
// trigger getOwnPropertyDescriptor & prop =>  Symbol(1)

Object.getOwnPropertyNames()

const proxy = new Proxy(foo, handler)
Object.getOwnPropertyNames(proxy)

// trigger ownKeys

Object.getOwnPropertySymbols()

const proxy = new Proxy(foo, handler)
console.log(Object.getOwnPropertySymbols(proxy))

// trigger ownKeys
// [ Symbol(1) ]

Object.keys()

const proxy = new Proxy(foo, handler)
console.log(Object.keys(proxy))

// trigger ownKeys
// trigger getOwnPropertyDescriptor & prop =>  id
// trigger getOwnPropertyDescriptor & prop =>  age
// trigger getOwnPropertyDescriptor & prop =>  sex
// [ 'id', 'sex' ]

自身 String类型属性 可枚举 键值集合

Object.values()

const proxy = new Proxy(foo, handler)
console.log(Object.values(proxy))


// trigger ownKeys
// trigger getOwnPropertyDescriptor & prop =>  id
// trigger getter & prop =>  id
// trigger getOwnPropertyDescriptor & prop =>  age
// trigger getOwnPropertyDescriptor & prop =>  sex
// trigger getter & prop =>  sex
// [ 'foo', 'man' ]

自身 String类型属性 可枚举 值集合

Object.getPrototypeOf()

const proxy = new Proxy(foo, handler)
console.log(Object.getPrototypeOf(proxy))

// trigger getPrototypeOf
// { num: 11 }

Object.setPrototypeOf()

const proxy = new Proxy(foo, handler)
console.log(Object.setPrototypeOf(proxy, { 'newProp': 'qux'}))
console.log(proxy.newProp)

// trigger setPrototypeOf
// { id: 'foo', sex: [Getter/Setter], [Symbol(1)]: 'symbol-value' }
// trigger getter & prop =>  newProp
// qux

Object.prototype.isPrototypeOf()

const obj = Object.create(foo)
const objProxy = new Proxy(obj, handler)
foo.isPrototypeOf(objProxy)

// trigger getPrototypeOf

Object.hasOwn(target, prop) 实验性

const proxy = new Proxy(foo, handler)
console.log(Object.hasOwn(proxy, 'num'))

// trigger getOwnPropertyDescriptor & prop =>  num
// false

Object.prototype.hasOwnProperty()

const proxy = new Proxy(foo, handler)
console.log(proxy.hasOwnProperty('id'))

// trigger getter & prop =>  hasOwnProperty
// trigger getOwnPropertyDescriptor & prop =>  id
// true

Object.is()

用来判断两个值是否是同一个值
=== 用来判断两个变量的 数据类型 值是否相等
== 判断两个变量的值 是否相等

区别:
=== 情况下
NaN === NaN 为false
0 === -0 0 === +0 为true
Object.is()
Object.is(NaN, NaN) 为true
Object.is(0, -0) 为false

console.log(NaN === NaN)
console.log(0 === -0)
console.log(0 === +0)
console.log(Object.is(NaN,NaN))
console.log(Object.is(0 === -0))
console.log(Object.is(0 === +0))

===

console.log(NaN === NaN) // false
console.log('' === ' ') // false
console.log(0 === -0) // true
console.log(0 === +0) // true
console.log(0.1 === 0.1000) // true
console.log(1 === 1.000) // true
console.log('a' + 'bcd' === 'abc' + 'd') // true 
console.log('a' + 'bdc' === 'abc' + 'd') // false


console.log(Object.is(0.1, 0.100)) // true
console.log(Object.is(1, 1.000)) // true

==

假值:false 0 '' null undefined NaN

console.log(1 == true)
// 假值:false 0  ''  null  undefined NaN
console.log(0 == false)
console.log(+0 == false)
console.log(-0 == false)
console.log(0 == '  ')
console.log('' == false)

console.log(false == false)
console.log(0 == 0)
console.log(null == null)
console.log(undefined == undefined)
// 以上结果全是true

console.log('' == '') //true
console.log('' == ' ') // false
console.log(false == ' ') // true


console.log(null == undefined) // true


console.log(null == 0)
console.log(null == false)
console.log(null == '')
console.log(undefined == 0)
console.log(undefined == false)
console.log(undefined == '')
// false
// false
// false
// false
// false
// false

console.log(NaN == 0)
console.log(NaN == false)
console.log(NaN == '')
console.log(NaN == null)
console.log(NaN == undefined)
console.log(NaN == NaN)
// 全是false

NaN与任何值都不相等,包括它自己。null 和 undefined 值相等,但是它们是不同类型的数据。在相等比较中,null 和 undefined 不允许被转换为其他类型的值。

'0' 是真值

console.log(!!'0') // true

console.log('0' == 1) // false
console.log('0' == true) // false

console.log('0' == 0) // true
console.log('0' == false) // true
console.log('+0' == false) // true

console.log('0' == '') // false
console.log('0' == null) // false
console.log('0' == undefined) // false

var a = new String("abcd);  //定义字符串“abcd”对象
var b = new String("abcd);  //定义字符串“abcd”对象
console.log(a === b);  //返回false
console.log(a == b);  //返回false
var a = null;
var b = undefined;
console.log((a > b || a == b) == (a >= b));  //返回false,表达式的值并非相等

Object.isExtensible()

const proxy = new Proxy(foo, handler)
console.log(Object.isExtensible(proxy))

trigger isExtensible
true

针对属性prop新增
针对原型prototype修改

Object.preventExtensions()

设置目标对象禁止扩展
主要针对属性新增与原型

const proxy = new Proxy(foo, handler)
Object.preventExtensions(proxy)
console.log(Object.isExtensible(proxy))
console.log(Object.isExtensible(foo))
console.log(proxy)

// 打印结果
// trigger preventExtensions
// trigger isExtensible
// false
// false



// 新增属性 失败
// proxy.newProp = 'newValue' // 不能返回操作是都成功,是否设置成功
console.log(Reflect.defineProperty(proxy, 'newProp', {
  value: 'newValue',
  writable: true
}))
// print
// trigger defineProperty
// false

// 新增属性2 失败
console.log(Reflect.set(proxy, 'newpProp', 'newValue'))
// trigger setter & prop =>  newpProp
// trigger getOwnPropertyDescriptor & prop =>  newpProp
// trigger defineProperty
// false

// 删除原有属性 成功
console.log(Reflect.deleteProperty(proxy, 'id'))
console.log(proxy)
// trigger deleteProperty
// true
// { sex: [Getter/Setter], [Symbol(1)]: 'symbol-value' }

// 修改原有属性 成功
console.log(Reflect.set(proxy, 'id', 'qux'))
console.log(foo.id)
// trigger setter & prop =>  id
// trigger getOwnPropertyDescriptor & prop =>  id
// trigger defineProperty
// true
// qux

// 修改原型 失败
console.log(Reflect.setPrototypeOf(proxy, { 'newProp': 'newValue' }))
// trigger setPrototypeOf
// false
// 不可修改原型 但是可以修改原型的属性与方法
console.log(Object.getPrototypeOf(proxy).newProp = 'newValue')
console.log(proxy.newProp)

Object.seal()

密封对象:
不可扩展 (不可新增属性,不可修改原型)
不可删除属性, 不可修改属性配置,
可以修改原有属性值

const proxy = new Proxy(foo, handler)
console.log(Object.seal(proxy))

// trigger preventExtensions
// trigger ownKeys
// trigger defineProperty
// trigger defineProperty
// trigger defineProperty
// trigger defineProperty
console.log(Object.getOwnPropertyDescriptors(proxy))
// 打印结果
{
  id: {
    value: 'foo',
    writable: true,
    enumerable: true,
    configurable: false
  },
  age: { value: 19, writable: true, enumerable: false, configurable: false },
  sex: {
    get: [Function: get],
    set: [Function: set],
    enumerable: true,
    configurable: false
  },
  [Symbol(1)]: {
    value: 'symbol-value',
    writable: true,
    enumerable: true,
    configurable: false
  }
}

Object.isSealed()

console.log(Object.isSealed(proxy)

trigger isExtensible
trigger ownKeys
trigger getOwnPropertyDescriptor & prop =>  id       
trigger getOwnPropertyDescriptor & prop =>  age      
trigger getOwnPropertyDescriptor & prop =>  sex      
trigger getOwnPropertyDescriptor & prop =>  Symbol(1)
true

Object.freeze()

冻结后 是
不可扩展isExtensible (属性不可新增, 原型不可修改)
属性不可删除 不可修改属性配置 configurable: false
属性不可修改 writable: false

freeze() 后,先冻结扩展性
然后遍历自身所有属性
没有getter setter的 属性全部定义为不可写,不可配置

const proxy = new Proxy(foo, handler)
Object.freeze(proxy)

// 打印结果
trigger preventExtensions
trigger ownKeys
trigger getOwnPropertyDescriptor & prop =>  id
trigger defineProperty
trigger getOwnPropertyDescriptor & prop =>  age
trigger defineProperty
trigger getOwnPropertyDescriptor & prop =>  sex
trigger defineProperty
trigger getOwnPropertyDescriptor & prop =>  Symbol(1)
trigger defineProperty

// 修改属性
foo.id = 'bar'
console.log(foo.id)

Object.isFrozen()

const proxy = new Proxy(foo, handler)
Object.isFrozen(proxy)

// trigger isExtensible
// false

Object.preventExtensions(proxy)
console.log(Object.isFrozen(proxy))
// trigger preventExtensions
// trigger isExtensible
// trigger ownKeys
// trigger getOwnPropertyDescriptor & prop =>  id
// false

Object.freeze(foo)
console.log(Object.isFrozen(proxy))

// trigger isExtensible
// trigger ownKeys
// trigger getOwnPropertyDescriptor & prop =>  id
// trigger getOwnPropertyDescriptor & prop =>  age
// trigger getOwnPropertyDescriptor & prop =>  sex
// trigger getOwnPropertyDescriptor & prop =>  Symbol(1)
// true


console.log(Object.getOwnPropertyDescriptors(proxy))
// 打印信息
/*
{
  id: {
    value: 'foo',
    writable: false,
    enumerable: true,
    configurable: false
  },
  age: {
    value: 19,
    writable: false,
    enumerable: false,
    configurable: false
  },
  sex: {
    get: [Function: get],
    set: [Function: set],
    enumerable: true,
    configurable: false
  },
  [Symbol(1)]: {
    value: 'symbol-value',
    writable: false,
    enumerable: true,
    configurable: false
  }
}
**/

Object.prototype.properyIsEnumerable()

const proxy = new Proxy(foo, handler)
console.log(proxy.propertyIsEnumerable('age'))

// trigger getter & prop =>  propertyIsEnumerable
// trigger getOwnPropertyDescriptor & prop =>  age
// false

Object.prototype.toLocaleString()

Object toLocaleString 返回调用 toString() 的结果。

const foo = function() {
  return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.toLocaleString ())

trigger getter & prop =>  toLocaleString
trigger getter & prop =>  toString
function () { [native code] }

Object.prototype.toString()

const foo = function() {
  return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.toString())

trigger getter & prop =>  toString
function () { [native code] }

Obeject.prototype.valueOf()

返回对象的原始值,很少用到

const foo = function() {
  return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.valueOf() === foo) // false
console.log(proxy.valueOf() === proxy) // true

trigger getter & prop =>  valueOf
 类似资料: