ECMAScript 6學(xué)習(xí)(六)

defineProperty()

學(xué)習(xí)書(shū)籍《ECMAScript 6 入門(mén) 》

Proxy


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

Proxy 可以理解成,在目標(biāo)對(duì)象之前架設(shè)一層“攔截”,外界對(duì)該對(duì)象的訪問(wèn),都必須先通過(guò)這層攔截,因此提供了一種機(jī)制,可以對(duì)外界的訪問(wèn)進(jìn)行過(guò)濾和改寫(xiě)。Proxy 這個(gè)詞的原意是代理,用在這里表示由它來(lái)“代理”某些操作,可以譯為“代理器”。

Proxy 構(gòu)造函數(shù)

var proxy = new Proxy(target,handler);

Proxy 對(duì)象的所有用法,都是上面這種形式,不同的只是handler參數(shù)的寫(xiě)法。其中,new Proxy()表示生成一個(gè)Proxy實(shí)例,target參數(shù)表示所要攔截的目標(biāo)對(duì)象,handler參數(shù)也是一個(gè)對(duì)象,用來(lái)定制攔截行為。

實(shí)例代碼:

var handler = {

? ? get: function(target, name) {

? ? ? ? if (name === 'prototype') {

? ? ? ? ? ? return Object.prototype;

? ? ? ? }

? ? ? ? return 'Hello, ' + name;

? ? },

? ? apply: function(target, thisBinding, args) {

? ? ? ? return args[0];

? ? },

? ?construct: function(target, args) {

? ? ? ? return {value: args[1]};

? ? }

};

var fproxy = new Proxy(function(x, y) {

? ? return x + y;

? }, handler);

fproxy(1, 2) ?// 1

new fproxy(1,2) // {value: 2}

fproxy.prototype === Object.prototype // true

fproxy.foo // "Hello, foo"

下面是 Proxy 支持的攔截操作一覽。

(1)get(target, propKey, receiver)

攔截對(duì)象屬性的讀取,比如proxy.fooproxy['foo']。

最后一個(gè)參數(shù)receiver是一個(gè)對(duì)象,可選,參見(jiàn)下面Reflect.get的部分。

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

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

(3)has(target, propKey)

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

(4)deleteProperty(target, propKey)

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

(5)ownKeys(target)

攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一個(gè)數(shù)組。該方法返回目標(biāo)對(duì)象所有自身的屬性的屬性名,而Object.keys()的返回結(jié)果僅包括目標(biāo)對(duì)象自身的可遍歷屬性。

(6)getOwnPropertyDescriptor(target, propKey)

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

(7)defineProperty(target, propKey, propDesc)

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

(8)preventExtensions(target)

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

(9)getPrototypeOf(target)

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

(10)isExtensible(target)

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

(11)setPrototypeOf(target, proto)

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

如果目標(biāo)對(duì)象是函數(shù),那么還有兩種額外操作可以攔截。

(12)apply(target, object, args)

攔截 Proxy 實(shí)例作為函數(shù)調(diào)用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)

(13)construct(target, args)

攔截 Proxy 實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如new proxy(...args)

get()

下面的例子使用get攔截,實(shí)現(xiàn)數(shù)組讀取負(fù)數(shù)的索引。


function createArray(...elements) {

? ? let handler = {

? ? ? ? get(target, propKey, receiver) {

? ? ? ? ? ? let index = Number(propKey);

? ? ? ? ? ? if (index < 0) {

? ? ? ? ? ? ? ? propKey = String(target.length + index);

? ? ? ? ? ? }

? ? ? ? ? ? ?return Reflect.get(target, propKey, receiver);

? ? ? ? }

? ? };

? ? let target = [];

? ? target.push(...elements);

? ? return new Proxy(target, handler);

}

let arr = createArray('a', 'b', 'c');

arr[-1] // c

該例子,通過(guò)判定index來(lái)對(duì)數(shù)組的角標(biāo)返回值進(jìn)行攔截過(guò)濾

if(index<0){

? ? propKey=String(target.length+index);

}

即當(dāng)index小于0時(shí),propkey也就是 arr[-1]? 傳入的-1的index,對(duì)其進(jìn)行修改,讓 propkey的值變?yōu)?(target.length+index)= 3+(-1)=2;

然后執(zhí)行反射函數(shù) Reflect;

Reflect.get(target, propKey, receiver)

通過(guò)字面意思翻譯以及上面代碼的返回值 可猜測(cè)到? Refect為反射函數(shù);

而該句的意思為:用過(guò)Reflect 調(diào)用 攔截對(duì)象 本身的get方法執(zhí)行;


利用 Proxy,可以將讀取屬性的操作(get),轉(zhuǎn)變?yōu)閳?zhí)行某個(gè)函數(shù),從而實(shí)現(xiàn)屬性的鏈?zhǔn)讲僮鳌?/p>


var pipe = (function () {

? ? return function (value) {

? ? ? ? var funcStack = [];

? ? ? ?var oproxy = new Proxy({} , {

? ? ? ? ? ? get : function (pipeObject, fnName) {

? ? ? ? ? ? ? ? if (fnName === 'get') {

? ? ? ? ? ? ? ? ? ?return funcStack.reduce(function (val, fn) {

? ? ? ? ? ? ? ? ? ? ? ? return fn(val);

? ? ? ? ? ? ? ? ? ?},value);

? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? funcStack.push(window[fnName]);

? ? ? ? ? ? ? ? return oproxy;

? ? ? ? ? }

? ? ? ?});

? ? ? ? return oproxy;

? ? ? }

? ? }());

var double = n => n * 2;

var pow? ? = n => n * n;

var reverseInt = n => n.toString().split("").reverse().join("") | 0;

pipe(3).double.pow.reverseInt.get; // 63

該例子用到了一個(gè)沒(méi)見(jiàn)過(guò)的方法也就是reduce();通過(guò)百度知道了 這是Array 數(shù)組里面的一個(gè)方法;

reduce()對(duì)數(shù)組中的所有元素調(diào)用指定的回調(diào)函數(shù)。該回調(diào)函數(shù)的返回值為累積結(jié)果,并且此返回值在下一次調(diào)用該回調(diào)函數(shù)時(shí)作為參數(shù)提供。

reduce()

也就是說(shuō)reduce方法的第一個(gè)參數(shù)是回調(diào)函數(shù),函數(shù)格式如下


reduce方法的回調(diào)函數(shù)

而回調(diào)函數(shù)的第一個(gè)參數(shù)為上次回調(diào)的值,如果首次調(diào)用該函數(shù),則參數(shù)的值為initalValue.

所以

funcStack.reduce(function (val, fn) {

return fn(val);

},value);

該行代碼的執(zhí)行結(jié)果為:?

? 第一次調(diào)用? val = value = 3? ; ?fn =? n => n * 2 ?; ? return 值 : 3*2 = 6;

? 第二次調(diào)用? val = 6 ; value = 3 ?; ?fn =? n => n * n ;? return 值 : 6*6 = 36;

? 第三次調(diào)用? val = 36 ; value = 3? ;? fn =? n =>n.toString().split("").reverse().join("") | 0 ?;??

? ? ? ? ? ? ? ? ? ? ? ?return 值 :把36變成字符串 然后分割 反轉(zhuǎn) 變成 '63' ,在轉(zhuǎn)換成 數(shù)字 ?63;

因此,最后的執(zhí)行結(jié)果為 63 .


set()

set方法用來(lái)攔截某個(gè)屬性的賦值操作。

假定Person對(duì)象有一個(gè)age屬性,該屬性應(yīng)該是一個(gè)不大于200的整數(shù),那么可以使用Proxy保證age的屬性值符合要求。

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');

? ? ? ? ? ?}

? ? ? ? }

? ? ? ? // 對(duì)于age以外的屬性,直接保存

? ? ? ? obj[prop] = value;

? ? ? }

? };

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

person.age = 100;

person.age // 100

person.age = 'young' // 報(bào)錯(cuò)

person.age = 300 // 報(bào)錯(cuò)


apply()

apply方法攔截函數(shù)的調(diào)用、callapply操作。

apply方法可以接受三個(gè)參數(shù),分別是目標(biāo)對(duì)象、目標(biāo)對(duì)象的上下文對(duì)象(this)和目標(biāo)對(duì)象的參數(shù)數(shù)組。

var handler = {

? ? apply (target, ctx, args) {

? ? ? ? return Reflect.apply(...arguments);

? ? }

};

下面是一個(gè)例子。

var target = function () { ?return 'I am the target'; ?};

var handler = {

? ? apply: function () {

? ? ? ? return 'I am the proxy';

? ? }

};

var p = new Proxy(target, handler);

p()

// "I am the proxy"

上面代碼中,變量p是 Proxy 的實(shí)例,當(dāng)它作為函數(shù)調(diào)用時(shí)(p()),就會(huì)被apply方法攔截,返回一個(gè)字符串。

下面是另外一個(gè)例子。

var twice = {

? ? apply (target, ctx, args) {

? ? ? ? return Reflect.apply(...arguments) * 2;

? ? }

};

function sum (left, right) {

? ? return left + right;

};

var proxy = new Proxy(sum, twice);

proxy(1, 2) // 6

proxy.call(null, 5, 6) // 22

proxy.apply(null, [7, 8]) // 30

上面代碼中,每當(dāng)執(zhí)行proxy函數(shù)(直接調(diào)用或call和apply調(diào)用),就會(huì)被apply方法攔截。

另外,直接調(diào)用Reflect.apply方法,也會(huì)被攔截。

Reflect.apply(proxy,null,[9,10])// 38


has()

has方法用來(lái)攔截HasProperty操作,即判斷對(duì)象是否具有某個(gè)屬性時(shí),這個(gè)方法會(huì)生效。典型的操作就是in運(yùn)算符。

下面的例子使用has方法隱藏某些屬性,不被in運(yùn)算符發(fā)現(xiàn)。

var handler = {

? ? has (target, key) {

? ? ? ? if (key[0] === '_') {

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ?return key in target;

? ? }

};

var target = { _prop: 'foo', prop: 'foo' };

var proxy = new Proxy(target, handler);

'_prop' in proxy // false

上面代碼中,如果原對(duì)象的屬性名的第一個(gè)字符是下劃線,proxy.has就會(huì)返回false,從而不會(huì)被in運(yùn)算符發(fā)現(xiàn)。

如果原對(duì)象不可配置或者禁止擴(kuò)展,這時(shí)has攔截會(huì)報(bào)錯(cuò)。

var obj = { a: 10 };

Object.preventExtensions(obj);

var p = new Proxy(obj, {

? ? has: function(target, prop) {

? ? ? ? return false;

? ? }

});

'a' in p // TypeError is thrown

上面代碼中,obj對(duì)象禁止擴(kuò)展,結(jié)果使用has攔截就會(huì)報(bào)錯(cuò)。也就是說(shuō),如果某個(gè)屬性不可配置(或者目標(biāo)對(duì)象不可擴(kuò)展),則has方法就不得“隱藏”(即返回false)目標(biāo)對(duì)象的該屬性。

值得注意的是,has方法攔截的是HasProperty操作,而不是HasOwnProperty操作,即has方法不判斷一個(gè)屬性是對(duì)象自身的屬性,還是繼承的屬性。

另外,雖然for...in循環(huán)也用到了in運(yùn)算符,但是has攔截對(duì)for...in循環(huán)不生效。

let stu1 = {name: '張三', score: 59};

let stu2 = {name: '李四', score: 99};

let handler = {

? ? has(target, prop) {

? ? ? ? if (prop === 'score' && target[prop] < 60) {

? ? ? ? ? ? console.log(`${target.name} 不及格`);

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? return prop in target;

? ? }

};

let oproxy1 = new Proxy(stu1, handler);

let oproxy2 = new Proxy(stu2, handler);

'score' in oproxy1

// 張三 不及格

// false

'score' in oproxy2

// true

for (let a in oproxy1) {

console.log(oproxy1[a]);

}

// 張三

// 59

for (let b in oproxy2) {

console.log(oproxy2[b]);

}

// 李四

// 99

上面代碼中,has攔截只對(duì)in循環(huán)生效,對(duì)for...in循環(huán)不生效,導(dǎo)致不符合要求的屬性沒(méi)有被排除在for...in循環(huán)之外。


construct()

construct方法用于攔截new命令,下面是攔截對(duì)象的寫(xiě)法。

var handler = {

? ? construct (target, args, newTarget) {

? ? ? ? return new target(...args);

? ? }

};

construct方法返回的必須是一個(gè)對(duì)象,否則會(huì)報(bào)錯(cuò)。

construct方法可以接受兩個(gè)參數(shù)。

? ? --target: 目標(biāo)對(duì)象

? ? --args:構(gòu)建函數(shù)的參數(shù)對(duì)象

var p = new Proxy(function () {}, {

? ? construct: function(target, args) {

? ? ? ? console.log('called: ' + args.join(', '));

? ? ? ? return { value: args[0] * 10 };

? ? }

});

(new p(1)).value

// "called: 1"

// 10


deleteProperty()

deleteProperty方法用于攔截delete操作,如果這個(gè)方法拋出錯(cuò)誤或者返回false,當(dāng)前屬性就無(wú)法被delete命令刪除。

var handler = {

? ? deleteProperty (target, key) {

? ? ? ? invariant(key, 'delete');

? ? ? ? return true;

? ? }

};

function invariant (key, action) {

? ? if (key[0] === '_') {

? ? ? ? throw new Error(`Invalid attempt to ${action} private "${key}" property`);

? ? }

}

var target = { _prop: 'foo' };

var proxy = new Proxy(target, handler);

delete proxy._prop

// Error: Invalid attempt to delete private "_prop" property

上面代碼中,deleteProperty方法攔截了delete操作符,刪除第一個(gè)字符為下劃線的屬性會(huì)報(bào)錯(cuò)。

注意,目標(biāo)對(duì)象自身的不可配置(configurable)的屬性,不能被deleteProperty方法刪除,否則報(bào)錯(cuò)。


defineProperty()

defineProperty方法攔截了Object.defineProperty操作。

var handler = {

? ? defineProperty (target, key, descriptor) {

? ? ? ? return false;

? ? }

};

var target = {};

var proxy = new Proxy(target, handler);

proxy.foo = 'bar'

// TypeError: proxy defineProperty handler returned false for property '"foo"'

上面代碼中,defineProperty方法返回false,導(dǎo)致添加新屬性會(huì)拋出錯(cuò)誤。

注意,如果目標(biāo)對(duì)象不可擴(kuò)展(extensible),則defineProperty不能增加目標(biāo)對(duì)象上不存在的屬性,否則會(huì)報(bào)錯(cuò)。另外,如果目標(biāo)對(duì)象的某個(gè)屬性不可寫(xiě)(writable)或不可配置(configurable),則defineProperty方法不得改變這兩個(gè)設(shè)置。


getOwnPropertyDescriptor()

getOwnPropertyDescriptor方法攔截Object.getOwnPropertyDescriptor,返回一個(gè)屬性描述對(duì)象或者undefined。

var handler = {

? ? getOwnPropertyDescriptor (target, key) {

? ? ? ? if (key[0] === '_') {

? ? ? ? return;

? ? ? ? }

? ? return Object.getOwnPropertyDescriptor(target, key);

? ?}

};

var target = { _foo: 'bar', baz: 'tar' };

var proxy = new Proxy(target, handler);

Object.getOwnPropertyDescriptor(proxy, 'wat')

// undefined

Object.getOwnPropertyDescriptor(proxy, '_foo')

// undefined

Object.getOwnPropertyDescriptor(proxy, 'baz')

// { value: 'tar', writable: true, enumerable: true, configurable: true }

上面代碼中,handler.getOwnPropertyDescriptor方法對(duì)于第一個(gè)字符為下劃線的屬性名會(huì)返回undefined。


getPrototypeOf()

getPrototypeOf方法主要用來(lái)攔截Object.getPrototypeOf()運(yùn)算符,以及其他一些操作。

? ? --Object.prototype.__proto__

? ? --Object.prototype.isPrototypeOf()

? ? --Object.getPrototypeOf()

? ? --Reflect.getPrototypeOf()

? ? --instanceof運(yùn)算符

var proto = {};

var p = new Proxy({}, {

? ? getPrototypeOf(target) {

? ? ? ? return proto;

? ? }

});

Object.getPrototypeOf(p) === proto // true

上面代碼中,getPrototypeOf方法攔截Object.getPrototypeOf(),返回proto對(duì)象。

注意,getPrototypeOf方法的返回值必須是對(duì)象或者null,否則報(bào)錯(cuò)。另外,如果目標(biāo)對(duì)象不可擴(kuò)展(extensible),getPrototypeOf方法必須返回目標(biāo)對(duì)象的原型對(duì)象。


isExtensible()?

isExtensible方法攔截Object.isExtensible操作。

var p = new Proxy({}, {

? ? isExtensible: function(target) {

? ? ? ? console.log("called");

? ? ? ? return true;

? ? }

});

Object.isExtensible(p)

// "called"

// true

上面代碼設(shè)置了isExtensible方法,在調(diào)用Object.isExtensible時(shí)會(huì)輸出called。

注意,該方法只能返回布爾值,否則返回值會(huì)被自動(dòng)轉(zhuǎn)為布爾值。

這個(gè)方法有一個(gè)強(qiáng)限制,它的返回值必須與目標(biāo)對(duì)象的isExtensible屬性保持一致,否則就會(huì)拋出錯(cuò)誤。


ownKeys()

ownKeys方法用來(lái)攔截以下操作。

? ? --Object.getOwnPropertyNames()

? ? --Object.getOwnPropertySymbols()

? ? --Object.keys()

注意,使用Object.keys方法時(shí),有三類屬性會(huì)被ownKeys方法自動(dòng)過(guò)濾,不會(huì)返回。

? ? --目標(biāo)對(duì)象上不存在的屬性

? ? --屬性名為 Symbol 值

? ? --不可遍歷(enumerable)的屬性

let target = {

? ? a: 1,

? ? b: 2,

? ? c: 3,

? ? [Symbol.for('secret')]: '4',

};

Object.defineProperty(target, 'key', {

? ? enumerable: false,

? ? configurable: true,

? ? writable: true,

? ? value: 'static'

});

let handler = {

? ? ownKeys(target) {

? ? ? ? return ['a', 'd', Symbol.for('secret'), 'key'];

? ? }

};

let proxy = new Proxy(target, handler);

Object.keys(proxy)

// ['a']

上面代碼中,ownKeys方法之中,顯式返回不存在的屬性(d)、Symbol 值(Symbol.for('secret'))、不可遍歷的屬性(key),結(jié)果都被自動(dòng)過(guò)濾掉。


preventExtensions()

preventExtensions方法攔截Object.preventExtensions()。該方法必須返回一個(gè)布爾值,否則會(huì)被自動(dòng)轉(zhuǎn)為布爾值。

這個(gè)方法有一個(gè)限制,只有目標(biāo)對(duì)象不可擴(kuò)展時(shí)(即Object.isExtensible(proxy)false),proxy.preventExtensions才能返回true,否則會(huì)報(bào)錯(cuò)。

var p = new Proxy({}, {

? ? preventExtensions: function(target) {

? ? ? ? return true;

? ? }

});

Object.preventExtensions(p) // 報(bào)錯(cuò)

上面代碼中,proxy.preventExtensions方法返回true,但這時(shí)Object.isExtensible(proxy)會(huì)返回true,因此報(bào)錯(cuò)。

為了防止出現(xiàn)這個(gè)問(wèn)題,通常要在proxy.preventExtensions方法里面,調(diào)用一次Object.preventExtensions。

var p = new Proxy({}, {

? ? preventExtensions: function(target) {

? ? ? ? ?console.log('called');

? ? ? ? Object.preventExtensions(target);

? ? ? ? return true;

? ? }

});

Object.preventExtensions(p)

// "called"

// true


setPrototypeOf()

setPrototypeOf方法主要用來(lái)攔截Object.setPrototypeOf方法。

var handler = {

? ? setPrototypeOf (target, proto) {

? ? ? ? throw new Error('Changing the prototype is forbidden');

? ?}

};

var proto = {};

var target = function () {};

var proxy = new Proxy(target, handler);

Object.setPrototypeOf(proxy, proto);

// Error: Changing the prototype is forbidden

上面代碼中,只要修改target的原型對(duì)象,就會(huì)報(bào)錯(cuò)。

注意,該方法只能返回布爾值,否則會(huì)被自動(dòng)轉(zhuǎn)為布爾值。另外,如果目標(biāo)對(duì)象不可擴(kuò)展(extensible),setPrototypeOf方法不得改變目標(biāo)對(duì)象的原型。


Proxy.revocable()

Proxy.revocable方法返回一個(gè)可取消的 Proxy 實(shí)例。

let target = {};

let handler = {};

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

proxy.foo = 123;

proxy.foo // 123

revoke();

proxy.foo // TypeError: Revoked

Proxy.revocable方法返回一個(gè)對(duì)象,該對(duì)象的proxy屬性是Proxy實(shí)例,revoke屬性是一個(gè)函數(shù),可以取消Proxy實(shí)例。上面代碼中,當(dāng)執(zhí)行revoke函數(shù)之后,再訪問(wèn)Proxy實(shí)例,就會(huì)拋出一個(gè)錯(cuò)誤。

Proxy.revocable的一個(gè)使用場(chǎng)景是,目標(biāo)對(duì)象不允許直接訪問(wèn),必須通過(guò)代理訪問(wèn),一旦訪問(wèn)結(jié)束,就收回代理權(quán),不允許再次訪問(wèn)。


this 問(wèn)題

雖然 Proxy 可以代理針對(duì)目標(biāo)對(duì)象的訪問(wèn),但它不是目標(biāo)對(duì)象的透明代理,即不做任何攔截的情況下,也無(wú)法保證與目標(biāo)對(duì)象的行為一致。主要原因就是在 Proxy 代理的情況下,目標(biāo)對(duì)象內(nèi)部的this關(guān)鍵字會(huì)指向 Proxy 代理。

const target = {

? ? m: function () {

? ? ? ? console.log(this === proxy);

? ? }

};

const handler = {};

const proxy = new Proxy(target, handler);

target.m() // false

proxy.m()? // true

上面代碼中,一旦proxy代理target.m,后者內(nèi)部的this就是指向proxy,而不是target。


實(shí)例:Web 服務(wù)的客戶端

Proxy 對(duì)象可以攔截目標(biāo)對(duì)象的任意屬性,這使得它很合適用來(lái)寫(xiě) Web 服務(wù)的客戶端。

const service = createWebService ('http://example.com/data');

service.employees().then(json => {

? ? const employees = JSON.parse(json);

? ? // ···

});

上面代碼新建了一個(gè) Web 服務(wù)的接口,這個(gè)接口返回各種數(shù)據(jù)。Proxy 可以攔截這個(gè)對(duì)象的任意屬性,所以不用為每一種數(shù)據(jù)寫(xiě)一個(gè)適配方法,只要寫(xiě)一個(gè) Proxy 攔截就可以了。

function createWebService(baseUrl) {

? ? return new Proxy({}, {

? ? ? ? get(target, propKey, receiver) {

? ? ? ? ?return () => httpGet(baseUrl+'/' + propKey);

? ? ? ? }

? ? });

}

同理,Proxy 也可以用來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的 ORM 層。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • 本人自學(xué)es6已經(jīng)有一段時(shí)間了,只覺(jué)得有些時(shí)候很是枯燥無(wú)味, 時(shí)而又覺(jué)得在以后的職業(yè)生涯中會(huì)很有用,因?yàn)閑s6的很...
    可樂(lè)_37d3閱讀 1,665評(píng)論 0 0
  • Proxy代理是一個(gè)共通的概念,可以起到攔截的作用。ES6里將Proxy標(biāo)準(zhǔn)化了,提供了Proxy構(gòu)造函數(shù),用來(lái)生...
    張歆琳閱讀 10,270評(píng)論 1 7
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,099評(píng)論 0 9
  • 上了賊船,就跟賊走。走自己的路,和愛(ài)情兵分兩路。是狼就煉好牙,是羊就煉好腿。 都說(shuō)姐漂亮,其實(shí)都是妝出來(lái)的小鳥(niǎo)雖小...
    jianghu000閱讀 281評(píng)論 0 1

友情鏈接更多精彩內(nèi)容