Proxy


概述

Proxy 用於修改某些操作的默認行為,等同於在語言層面做出修改,所以屬於一種“元編程”(meta programming),即對編程語言進行編程。

Proxy 可以理解成,在目標對象之前架設一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,可以譯為“代理器”。

基本使用

let obj = {
  a: 1,
  b: 2
}

let proxyObj = new Proxy(obj, {
  get: function() {
      // 攔截了既有的操作,返回自己的邏輯
      return "獲取值的內容"
  },
  set: function() {
      console.log("設置值的內容");
  }
})

console.log(proxyObj.a);
proxyObj.b = 20
console.log(proxyObj);

 

 

 proxyObj是設置可以攔截的對象,第一個obj參數是對應要攔截的對象內容,第二個對象參數是攔截行為,所有的行為在一個對象中

行為的內部可以設置參數

let obj = {
  a: 1,
  b: 2
}
let proxyObj = new Proxy(obj, {
  get: function(target, key) {
      // 攔截了既有的操作,返回自己的邏輯
      return `屬性${key},屬性值:${target[key]}`
  },
  set: function(target, key, value) {
      console.log(`屬性${key},屬性值:${target[key]},要設置的參數:${value}`);
  }
})
console.log(proxyObj.a);
proxyObj.b = 20
console.log(proxyObj);

 

 

 set方法主要的參數有兩個,第一個target指的目標對象,key表示獲取的該對象的key,

第二個set方法主要的參數有三個,第一個target指的目標對象,key表示獲取的該對象的key,value表示要設置的value

Proxy可以當做原型對象

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 1;
  }
});

let obj = Object.create(proxy);
console.log(obj.a)

 

 

 get方法

get方法用於攔截某個屬性的讀取操作。

var person = {
  name: "小明"
};

var proxy = new Proxy(person, {
  get: function(target, property) {
    // 判斷當前的key是否在對應的對象上,也就是查詢對象上有沒有要查的這個key
if (property in target) {
// 如果有就返回這個值
      return target[property];
} else {
// 沒有則拋出錯誤
      throw new ReferenceError("Property \"" + property + "\" does not exist.");
    }
  }
});

console.log(proxy.name )
console.log(proxy.age )

 

 

 

 get方法內部有三個參數

let obj = {
  a: 1,
  b: 2
}

let proxObj = new Proxy(obj, {
  get: function(target, key, receiver) {
      // 攔截了既有的操作,返回自己的邏輯
      return `屬性${key},屬性值:${target[key]}`
  }
})
console.log(proxObj.a);

 

 

 第一個target表示接受對象,第二個是獲取的key,第三個表示操作對象

set方法

set方法用來攔截某個屬性的賦值操作。

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // 對於age以外的屬性,直接保存
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

console.log(person.age )// 100
person.age = 'young' // 報錯
person.age = 300 // 報錯

 

 

 

 set方法一共有4個參數,第一個參數是接受的對象,第二個參數是設置的key,第三個是設置值,第四個參數是操作對象

let obj = {
  a: 1,
  b: 2
}
let proxObj = new Proxy(obj, {
  set: function(target, key, value, receiver) {
      console.log(receiver);
      // 攔截了既有的操作,返回自己的邏輯
      return target[key] = "3"
  }
})
proxObj.b = 20
console.log(proxObj);

 

 

 apply方法

apply方法攔截函數的調用、call和apply操作。

var twice = {
  apply(target, ctx, args) {
      // Reflect.apply(...arguments)返回是對參數的累加結果
      return Reflect.apply(...arguments) * 2;
  }
};

function sum(left, right) {
  // 累加
  return left + right;
};
var proxy = new Proxy(sum, twice);
console.log(proxy(1, 2) )
console.log(proxy.call(null, 5, 6) )
console.log(proxy.apply(null, [7, 8])) 

 

 

 construct方法

construct方法用於攔截new命令,下面是攔截對象的寫法。

var p = new Proxy(function() {}, {
  construct: function(target, args) {
    console.log('called: ' + args.join(', '));
    return { value: args[0] * 10 };
  }
});

new p(1).value

 

 

 construct方法返回的必須是一個對象,否則會報錯。

var p = new Proxy(function() {}, {
  construct: function(target, argumentsList) {
    return 1;
  }
});

new p() 

 

 

 

 Proxy 支持的攔截操作

對於可以設置、但沒有設置攔截的操作,則直接落在目標對象上,按照原先的方式產生結果。

(1)get(target, propKey, receiver)

         攔截對象屬性的讀取,比如proxy.fooproxy['foo']

         最后一個參數receiver是一個對象,可選。

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

         攔截對象屬性的設置,比如proxy.foo = vproxy['foo'] = v,返回一個布爾值。

(3)has(target, propKey)

         攔截propKey in proxy的操作,返回一個布爾值。

(4)deleteProperty(target, propKey)

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

(5)ownKeys(target)

         攔截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy),返回一個數組。該方法返回目標對象所有自身的屬性的屬性名,而Object.keys()的返回結             果僅包括目標對象自身的可遍歷屬性。

(6)getOwnPropertyDescriptor(target, propKey)

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

(7)defineProperty(target, propKey, propDesc)

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

(8)preventExtensions(target)

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

(9)getPrototypeOf(target)

         攔截Object.getPrototypeOf(proxy),返回一個對象。

(10)isExtensible(target)

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

(11)setPrototypeOf(target, proto)

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

         如果目標對象是函數,那么還有兩種額外操作可以攔截。

(12)apply(target, object, args)

         攔截 Proxy 實例作為函數調用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)

(13)construct(target, args)

         攔截 Proxy 實例作為構造函數調用的操作,比如new proxy(...args)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM