关于javascript:js代理与反射ProxyReflect

代理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)的汇合

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据