关于javascript:js代理与反射ProxyReflect

66次阅读

共计 6964 个字符,预计需要花费 18 分钟才能阅读完成。

代理 Proxy

用于创立一个对象的代理,实现基本操作的 拦挡 自定义,对外界的拜访进行过滤与改写

const p = new Proxy(target,handler)

target:要拦挡的 指标对象
handler:要拦挡的 行为
示例

const o = {a: 1, b: 2}
const p = new Proxy(o, {get(target, key, receiver) {console.log(`getting ${key}!`);
        return target[key]
    }
})
console.log(p.a);
setting a!
1

对象 o 属性读取的拦挡

target 能够是一个空对象,那么拦挡操作会间接作用在 Proxy 的实例化对象

1 handler 拦挡操作

  1. get()
  2. set()
  3. has()
  4. deleteProperty()
  5. ownKeys()
  6. getOwnPropertyDescriptor()
  7. defineProperty()
  8. apply()
  9. getPrototypeOf()
  10. setPrototypeOf()
  11. construct()
  12. isExtensible()
  13. preventExtensions()

1.1 get(target,key,receiver)

拦挡 读取 操作
target:指标对象
key:读取的属性名
receiver:Proxy 或继承 Proxy 的对象

const p = new Proxy({}, {get(target, key, receiver) {console.log(key);
        console.log(target);
        console.log(receiver);
        return target[key]
    }
})
p.a = 2
console.log(p.a);

1.2 set(target,key,value,receiver)

拦挡 赋值 操作
value:属性要赋于的值

const p = new Proxy({}, {set(target, key, value, receiver) {console.log(value);
        target[key] = value
    },
})
p.a = 2
console.log(p.a);
2
2

能够对设置的值进行判断,再决定是否进行赋值操作
在数据发生变化时,能够自动更新 DOM,实现数据绑定

1.3 apply(target,object,args)

拦挡 函数调用,call 办法、apply 办法
target:指标对象(函数)
object:被调用时的上下文对象
args:调用时的参数数组

function sum(num1, num2) {return num1 + num2}
const p = new Proxy(sum, {apply(target, obj, args) {console.log(obj);
        return target(...args)
    }
})
console.log(p(2, 3));
p.apply(null, [2, 3])
undefined
5
null

1.4 has(target,key)

拦挡 in 操作 返回 布尔值

const o = {_prop: "公有属性", prop: "foo"}
const p = new Proxy(o, {has(target, key) {if (key.startsWith("_")) {return false}
        return key in target
    }
})
console.log("_prop" in p);//false
console.log("prop" in p);//true

对于不可配置的属性,has 拦挡会报错
for…in 循环能够拜访到 has 拦挡的属性

1.5 construct(target,args)

拦挡 new 操作 返回一个 对象

function Student(name, age) {
    this.name = name;
    this.age = age
}
const p = new Proxy(Student, {construct(target, args) {console.log("new 操作");
        return new target(...args)
    }
})
const p1 = new p("张三", 18)
console.log(p1);
'new 操作'
{name:"张三",age:18}

1.6 deleteProperty(target,key)

拦挡 delete 操作 返回 布尔值

const o = {_prop: "公有属性", prop: "foo"}
const p = new Proxy(o, {deleteProperty(target, key) {if (key.startsWith("_")) {return false}
        return delete target[key]
    }
})
console.log(delete p._prop);//false
console.log(delete p.prop);//true

拦挡不可配置的属性会报错

1.7 defineProperty(target,key,descriptor)

拦挡 Object.defineProperty(), 返回 布尔值

const p = new Proxy({}, {defineProperty(target, key, descriptor) {target[key] = descriptor.value
        return true
    }
})
Object.defineProperty(p, 'b', {value: "0"})
console.log(p.b);//"0"

对象不可扩大时,则不能增加指标对象不存在的属性
不可写与不可配置,不能拦挡批改这两个设置

1.8 getOwnPropertyDescriptor(target,key)

拦挡 Object.getOwnPropertyDescriptor(),返回属性的 形容对象 或者undefined

const o = {_prop: "公有属性", prop: "foo"}
const p = new Proxy(o, {getOwnPropertyDescriptor(target, key) {if (key.startsWith("_")) {return undefined}
        return Object.getOwnPropertyDescriptor(target, key)
    }
})
console.log(Object.getOwnPropertyDescriptor(p, "_prop"));
console.log(Object.getOwnPropertyDescriptor(p, "prop"));
undefined
{value:"foo",writable:true,enumerable:true,configurable:true}

1.9 getProptypeOf(target)

拦挡 获取对象原型 的操作,返回一个对象
相干操作

  1. Object.prototype.__proto__
  2. Object.prototype.isPrototypeOf()
  3. Object.getPrototypeOf()
  4. Reflect.getPrototypeOf()
  5. instanceof
function Student(name) {this.name = name}
const std = new Student("张三")
let n = 1
const p = new Proxy(std, {getPrototypeOf(target) {console.log(` 拦挡获取原型的操作 ${n++}`);
        return Object.getPrototypeOf(target)
    }
})
console.log(Object.getPrototypeOf(p) === Student.prototype);
console.log(p instanceof Student);
console.log(Student.prototype.isPrototypeOf(p));
'拦挡获取原型的操作 1'
true
'拦挡获取原型的操作 2'
true
'拦挡获取原型的操作 3'
true

1.10 setPrototypeOf(target,proto)

拦挡 Object.setPrototypeOf(),返回 布尔值

function Student(name) {this.name = name}
const std = new Student("张三")
const p = new Proxy(std, {setPrototypeOf(target, proto) {console.log(` 拦挡设置原型的操作 `);
        return Object.setPrototypeOf(target, proto)
    }
})
Object.setPrototypeOf(p, Object.create(null))
console.log(Object.getPrototypeOf(p));
'拦挡设置原型的操作'
{}

不可扩大的对象不能批改原型

1.11 ownKeys(target)

拦挡 属性名的读取 操作,返回一个 数组
相干操作

  1. Object.getOwnPropertyNames()
  2. Object.getOwnPropertySymbols()
  3. Object.keys()
let foo = Symbol("foo")
const o = {
    a: 1,
    [foo]: "foo"
}
Object.defineProperty(o, "b", {
    value: "bar",
    enumerable: false
})
let n = 1;
const p = new Proxy(o, {ownKeys(target) {console.log(` 拦挡读取属性名操作 ${n++}`);
        return Reflect.ownKeys(target)
    }
})
console.log(Object.keys(p));
console.log(Object.getOwnPropertyNames(p));
console.log(Object.getOwnPropertySymbols(p));
'拦挡读取属性名操作 1'
['a']
'拦挡读取属性名操作 2'
['a','b']
'拦挡读取属性名操作 3'
[Symbol(foo)]

1.12 isExtensible(target)

拦挡 对象扩展性判断 的操作,返回一个 布尔值
相干操作

  1. Object.isExtensible()
  2. Object.isFrozen()
  3. Object.isSealed()
const o = {a: 1}
Object.seal(o)
const p = new Proxy(o, {isExtensible(target) {console.log("拦挡");
        return Object.isExtensible(target)
    }
})
console.log(Object.isExtensible(p));
console.log(Object.isFrozen(p));
console.log(Object.isSealed(p));
'拦挡'
false
'拦挡'
false
'拦挡'
true

1.13 preventExtensions(target)

拦挡 批改对象扩展性 的操作,返回一个 布尔值
相干操作

  1. Object.preventExtensions()
  2. Object.seal()
  3. Object.freeze()
const o1 = {a: 1}
const o2 = {b: 2}
const p = new Proxy(o2, {preventExtensions(target) {console.log("拦挡");
        if (target === o1) {return false}
        return Object.preventExtensions(target)
    }
})
Object.preventExtensions(p)
Object.seal(p)
Object.freeze(p)
console.log(Object.isExtensible(p));
拦挡
拦挡
拦挡
false

2 Proxy 上的办法与属性

Proxy.revocable(target,handler)

返回一个可勾销的 Proxy 实例

const {proxy,revoke} = Proxy.revocable(target,handler)

proxy:Proxy 的实例
revoke:勾销代理的办法

const o = {a: 1}
const {proxy:p, revoke} = Proxy.revocable(o, {})
console.log(p.a);//1
revoke()
console.log(p.a);//TypeError : Revoked

应用场景:指标对象必须通过代理能力拜访,拜访完结后发出代理权,不容许再次拜访

反射 Reflect

一个 内置对象 拦挡操作 ,不是一个函数对象,不可结构
所有的属性和办法都是动态的,相似于 Math 对象
静态方法与 Proxy 的 handler 中的操作同名

根本与 Object 上的办法雷同,只有轻微上的差异

Reflect 的静态方法

  1. get(target,name,receiver)
  2. set(target,name,value,receiver)
  3. has(obj,name)
  4. deleteProperty(obj,name)
  5. construct(target,args)
  6. getPrototypeOf(obj)
  7. setPrototypeOf(obj,proto)
  8. apply(func,thisArg,atgs)
  9. defineProperty(target,key,attr)
  10. getOwnPropertyDescriptor(target,key)
  11. isExtensible(target)
  12. preventExtensions(target)
  13. ownKeys(target)

1 get set

Object 上没有这两个办法

const o = {
    a: 1,
    get b() {return this.foo},
    set b(val) {return this.foo = val}
}
const b = {foo: 2}
console.log(Reflect.set(o, 'a', "1"));//true
console.log(Reflect.get(o, 'a'));//"1"
console.log(Reflect.set(o, 'b', "2", b));//true
console.log(Reflect.get(o, 'b', b));//"2"

给属性部署 get 与 set 办法,须要指定绑定的对象 receiver

2 has

Reflect.has(obj,name) 等价于 name in obj

3 deleteProperty

Reflect.deleteProperty(obj,name) 等价于 delete obj[name]

4 construct

Reflect.construct(target,args) 等价于 new target(…args)

5 getPrototypeOf setPrototypeOf

Reflect.getPrototypeOf(obj) 等价于 Objcet.getPrototype(obj)

前者第一个参数不是对象间接报错,后者会先转化为对象再操作

Reflect.setPrototypeOf(obj,proto) 等价于 Objcet.setPrototypeOf(obj,proto)

前者第一个参数不是对象间接报错,后者返回参数自身
第一个参数为 undefined 或 null,两者都报错

6 apply

Reflect.apply(func,thisArg,args) 等价于 Function.prototype.apply.call(func,thisArg,args) 等价于 func.apply(thisArg,args)

相当先于把 Fucntion.prototype.apply 绑定到 func 上,thisArg,args 作为 apply 的参数
因为 call 绑定后会立刻调用,则相当于 func.call(thisArgs,args)

7 defineProperty getOwnPropertyDescriptor

Reflect.definProperty(target,key,attr) 等价于 Object.defineProperty(target,key,descriptor)

前者第一个参数不是对象,间接报错

Refeclt.getOwnPropertyDescriptor(target,key) 等价于 Object.getOwnPropertyDescriptor(target,key)

前者第一个参数不是对象报错,后者返回 undefined

8 isExtensible preventExtensions

Reflect.isExtensible(target) 等价于 Objcet.isExtensible(target)

非对象,前者报错,后者返回 false

Reflect.preventExtensions(target) 等价于 Objcet.prevetExtensions(target)

非对象,前者报错,后者返回原参数

9 ownKeys

Reflect.ownKeys(target) 返回对象的所有属性
等价于 Objcet.getOwnPropertyNames(target)与 Objcet.getOwnPropertySymbols(target)的汇合

正文完
 0