最全面,最有良心的Proxy入門總結

Proxy

什麼Proxy?

proxy是ES6,新增的一個「攔截器」,也能夠理解成是ES6,新增的一種元變編程功能。es6

做用

proxy用於修改某些操做的默認行爲,等同於在語言層面做出修改。web

🌰

let proxy = new Proxy({},{
    get:function(target,property){
        return 35
    }
})

proxy.xxx //35
複製代碼

Proxy構造函數的解釋編程

Proxy構造函數接受兩個參數,第一個參數是所要代理的目標對象;第二個參數是一個配置對象,對於每個被代理的操做,須要提供一個對應的處理函數,該函數將攔截對應的操做。數組

Proxy配置對象的全部選項

1.get(target,propKey,receiver)

攔截對象屬性的讀取,target是被代理的對象,propKey是須要攔截的鍵,receiver是一個可選的參數。app

🌰編輯器

let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    getfunction (target, key{
        console.log(target, key)
        return target[key]
    }
})

console.log(proxy.name)

複製代碼

2.set(target,propKey,value,receiver)

攔截對象屬性的設置,target是被代理的對象,propKey是須要攔截的鍵,value是要設置的值,receiver是一個可選的參數。函數

🌰ui

let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    setfunction (target, key, value{
        return target[key] = value
    }
})

proxy.name = 'yuefengsu'

console.log(proxy.name)

複製代碼

3.has(target,propKey)

攔截propKey in target的操做,返回一個布爾值。this

🌰spa




let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {

    has:function(target,key){

        console.log(target,key)

        return key in target

    }
})

console.log('name' in proxy)
複製代碼

若是原對象不可配置或者禁止擴展,那麼這是has攔截會報錯;還有has方法攔截的是HasProperty,而不是HasOwnProperty,因此has方法不判斷一個屬性是對象自身仍是繼承的屬性。

4.deleteProperty(target,propKey)

攔截 delete target[propKey]的操做,返回一個布爾值。


let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {

    deletePropertyfunction (target, key{

        console.log(target, key)

        if(!(key in target)) throw TypeError('不存在的key')

        return delete [target, key]

    }
})

console.log(delete proxy['name'])
複製代碼

目標對象自身的不可配置的屬性不能被deleteProperty方法刪除,不然會報錯。

5.ownKeys(target)

攔截Object.getOwnPropertyNames(proxy),Object.getOwnPropertySymbols(proxy),Object.keys(proxy),返回一個數組,該方法返回目標對象因此自身屬性的屬性名。




let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {

    ownKeys:function(target){

        console.log(target)

        return ['name']

    }
})

console.log(Object.keys(proxy))

複製代碼

ownKeys方法返回的數組成員只能是字符串或者Symbol值,若是是其餘類型的值,或者返回的根本不是數組,就會報錯;若是目標對象自身包含不可配置的屬性,則該屬性必須ownKeys方法返回,不然也會報錯;若是目標對象是不可擴展的,這時ownKeys方法返回的數組中必須包含原對象的因此屬性,且不能包含多餘的屬性,不然也會報錯。

6.getOwnPropertyDescriptor(target,propKey)

攔截Object.getOwnPropertyDescriptor(proxy,propKey),返回屬性的描述對象。




let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {

    getOwnPropertyDescriptor:function(target,key){

        console.log(target,key)

        return Object.getOwnPropertyDescriptor(target,key)

    }
})


console.log(Object.getOwnPropertyDescriptor(obj,'name'))

複製代碼

7.defineProperty(target,peopKey,propDesc)

攔截Object.defineProperty(proxy,propKey,propDesc),Object.defineProperties(proxy,propDesc),返回一個布爾值。




let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    defineProperty:function(target,key,desc){

        console.log(target,key,desc)

        return true
    }
})


console.log(Object.defineProperty(proxy,'name',{}))
複製代碼

若是目標對象不可擴展,則defineProperty不能增長目標對象中不存在的屬性,不然會報錯,另外,若是目標對象的某個屬性不可寫或者不可配置,則defineProperty方法不得改變這兩個設置。

8.preventExtensions(target)

攔截Object.preventExtensions(proxy),返回一個布爾值。




let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {

    preventExtensions:function(target){

        console.log(target)

        Object.preventExtensions(target)

        return true
    }
})

console.log(Object.preventExtensions(proxy))
複製代碼

這個方法有一個限制,只有目標對象不可擴展(既Obeject.preventExtensions(proxy)爲false)proxy.preventExtensions才能返回true,不然會報錯。

9.getPrototypeOf(target)

攔截Object.getPrototypeOf(proxy),返回一個對象。具體攔截以下👇

  • Object.prototype. proto
  • Object.prototype.isPrototypeOf()
  • Object.getPrototypeOf()
  • Reflect.getPrototypeOf()
  • instanceof
let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    getPrototypeOf:function(target){
        console.log(target)
        return obj
    }
})


console.log(Object.getPrototypeOf(proxy))
複製代碼

getPrototypeOf方法的返回值必須是對象或者是null,不然會報錯。另外,若是目標對象不可擴展,getPrototypeOf方法必須返回目標對象的原型對象。

10.isExtensible(target)

攔截Object.isExtensible(proxy),返回一個布爾值。

let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    isExtensible:function(target){
        console.log(target)
        return true
    }
})


console.log(Object.isExtensible(proxy))
複製代碼

該方法只能返回布爾值,不然返回的值會被自動轉爲布爾值。

11.setPrototypeOf(target,proto)

攔截Object.setPrototypeOf(proxy,proto),返回一個布爾值。

let obj = {
    name"yuefeng"
}

let proxy = new Proxy(obj, {
    setPrototypeOf:function(target,proto){
        console.log(target,proto)
        target.prototype = proto
        return true
    }   
})


console.log(Object.setPrototypeOf(proxy,obj))
複製代碼

該方法只能返回布爾值,不然會被自動轉爲布爾值。另外,若是目標對象不可擴展,setPrototypeOf方法不得改變目標對象的原型。

12.apply(target,object,args)

攔截Proxy實例,並將其做爲函數調用的操做,好比proxy(...args)、proxy.call(object,...args)、proxy.apply(object,...args)。

let proxy = new Proxy(Person, {
    apply:function(target,ctx,args){
        console.log(target,ctx,args)
        return 'i am a boy'
    }
})

function Person (){
    return 'i am a gril'
}

console.log(proxy())
複製代碼

13.construct(target,args)

攔截Proxy實例做爲構造函數調用的操做,好比new proxy(...args)。


let proxy = new Proxy(Person, {
    construct:function(target,args){
        console.log(target,args)
        return {value:'18'}
    }
})

function Person (){
    return 'i am a gril'
}

console.log(new proxy().value)
複製代碼

construct方法必須返回一個對象,不然會報錯。

完整代碼👇


let proxy = new Proxy({}, {
    getfunction (target, key{
        console.log(target, key)
        return target[key]
    },
    setfunction (target, key, value{

        return target[key] = value

    },
    hasfunction (target, key{

        console.log(target, key)

        return key in target

    },
    deletePropertyfunction (target, key{

        console.log(target, key)

        if(!(key in target)) throw TypeError('不存在的key')

        return delete [target, key]

    },
    ownKeys:function(target){

        console.log(target)

        return ['name']

    },
    getOwnPropertyDescriptor:function(target,key){

        console.log(target,key)

        return Object.getOwnPropertyDescriptor(target,key)

    },
    defineProperty:function(target,key,desc){

        console.log(target,key,desc)

        return true
    },
    preventExtensions:function(target){

        console.log(target)

        Object.preventExtensions(target)

        return true
    },
    getPrototypeOf:function(target){
        console.log(target)
        return obj
    },
    isExtensible:function(target){
        console.log(target)
        return true
    },
    setPrototypeOf:function(target,proto){
        console.log(target,proto)
        target.prototype = proto
        return true
    },
    apply:function(target,ctx,args){
        console.log(target,ctx,args)
        return 'i am a boy'
    },
    construct:function(target,args){
        console.log(target,args)
        return {value:'18'}
    }
})

複製代碼

注意⚠️問題

this問題

Proxy能夠代理針對目標對象的訪問,但它不是目標對象的透明代理,既不作任何攔截的狀況下也沒法保證於目標對象的行爲一致。主要緣由就是Proxy代理的狀況下,目標對象內部的this關鍵字會指向Proxy代理

🌰

const target ={
    m:function(){
        console.log(this === proxy)
    }
}

const proxy = new Proxy({},{})

target.m() // false

proxy.m() // true
複製代碼

參考資料

  • 《es6標準入門》
相關文章
相關標籤/搜索