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)
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/construct
const foo = function() {
return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.constructor)
// trigger getter & prop => constructor
// [Function: Function]
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对象无关
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
const proxy = new Proxy(foo, handler)
Object.defineProperty(proxy, 'name', {
value: 'name-value',
enumerable: true
})
// trigger defineProperty
console.log(proxy)
// 不会触发捕获器
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
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))
能根据**键值对列表 ** 生成对象
不会触发捕获器
便于map 结构转对象
const obj = Object.fromEntries(map)
const proxy = new Proxy(foo, handler)
Object.getOwnPropertyDescriptor(proxy, 'age')
// trigger getOwnPropertyDescriptor & prop => age
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)
const proxy = new Proxy(foo, handler)
Object.getOwnPropertyNames(proxy)
// trigger ownKeys
const proxy = new Proxy(foo, handler)
console.log(Object.getOwnPropertySymbols(proxy))
// trigger ownKeys
// [ Symbol(1) ]
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类型属性 可枚举 键值集合
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类型属性 可枚举 值集合
const proxy = new Proxy(foo, handler)
console.log(Object.getPrototypeOf(proxy))
// trigger getPrototypeOf
// { num: 11 }
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
const obj = Object.create(foo)
const objProxy = new Proxy(obj, handler)
foo.isPrototypeOf(objProxy)
// trigger getPrototypeOf
const proxy = new Proxy(foo, handler)
console.log(Object.hasOwn(proxy, 'num'))
// trigger getOwnPropertyDescriptor & prop => num
// false
const proxy = new Proxy(foo, handler)
console.log(proxy.hasOwnProperty('id'))
// trigger getter & prop => hasOwnProperty
// trigger getOwnPropertyDescriptor & prop => id
// true
用来判断两个值是否是同一个值
===
用来判断两个变量的 数据类型 值是否相等
==
判断两个变量的值 是否相等
区别:
===
情况下
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,表达式的值并非相等
const proxy = new Proxy(foo, handler)
console.log(Object.isExtensible(proxy))
trigger isExtensible
true
针对属性prop新增
针对原型prototype修改
设置目标对象禁止扩展
主要针对属性新增与原型
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)
密封对象:
不可扩展 (不可新增属性,不可修改原型)
不可删除属性, 不可修改属性配置,
可以修改原有属性值
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
}
}
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
冻结后 是
不可扩展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)
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
}
}
**/
const proxy = new Proxy(foo, handler)
console.log(proxy.propertyIsEnumerable('age'))
// trigger getter & prop => propertyIsEnumerable
// trigger getOwnPropertyDescriptor & prop => age
// false
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] }
const foo = function() {
return 1 + 1
}
const proxy = new Proxy(foo, handler)
console.log(proxy.toString())
trigger getter & prop => toString
function () { [native code] }
返回对象的原始值,很少用到
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