-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
会 Proxy 这么了不起吗 #14
Comments
get(target, propKey, receiver)
let proxy = new Proxy({}, {
get (target, name) {
console.log('getting ' + name)
return target[name]
}
})
proxy.hello // getting hello
// 接上面代码
let obj = Object.create(proxy)
obj.foo // getting foo
const proxy = new Proxy({}, {
get: function(target, property, receiver) {
return receiver;
}
});
proxy.getReceiver === proxy // true
const d = Object.create(proxy);
d.a === d // true 上面代码中, 如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。 const target = Object.defineProperties({}, {
foo: {
value: 123,
writable: false,
configurable: false
},
});
const handler = {
get(target, propKey) {
return 'abc';
}
};
const proxy = new Proxy(target, handler);
proxy.foo
// TypeError: Invariant check failed 更多应用 1. 使用 function createArray (...elements) {
let handler = {
get (target, key, receiver) {
let index = Number(key)
if (index < 0) {
key = String(target.length + index)
}
return Reflect.get(target, key, receiver)
}
}
let target = []
target.push(...elements)
return new Proxy(target, handler)
}
let arr = createArray(1, 2, 3)
arr[-1] // 3 2. 链式操作 let pipe = (function () {
return function (value) {
let funcStack = []
let oProxy = new Proxy({}, {
get (pipObj, fnName) {
if (fnName === 'get') {
return funcStack.reduce((val, fn) => fn(val), value)
}
funcStack.push(window[fnName])
return oProxy
}
})
return oProxy
}
}())
let double = n => n * 2
let pow = n => n * n
let reverseInt = n => n.toString().split('').reverse().join('') || 0
pipe(3).double.pow.reverseInt.get // 63 3. 生成各种 DOM 节点的通用函数 let dom = new Proxy({}, {
get (target, property) {
return function (attrs = {}, ...children) {
const el = document.createElement(property)
for (let prop of Object.keys(attrs)) {
el.setAttribute(prop, attrs[prop])
}
for (let child of children) {
if (typeof child === 'string') {
child = document.createTextNode(child)
}
el.appendChild(child)
}
return el
}
}
})
const el = dom.div({},
'Hello, my name is ',
dom.a({href: '//example.com'}, 'Mark'),
'. I like:',
dom.ul({},
dom.li({}, 'The web'),
dom.li({}, 'Food'),
dom.li({}, '…actually that\'s it')
)
)
document.body.appendChild(el) |
Proxy实现一个简单的双向绑定的 todo list<div id="app">
<input type="text" id="input">
<div>
TODO:
<span id="text"></span>
</div>
<div id="btn">Add To Todo List</div>
<ul id="list"></ul>
</div> const input = document.getElementById('input')
const text = document.getElementById('text')
const list = document.getElementById('list')
const btn = document.getElementById('btn')
let render
const inputObj = new Proxy({}, {
get (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
if (key === 'text') {
input.value = value
text.innerHTML = value
}
return Reflect.set(target, key, value, receiver)
}
})
class Render {
constructor (arr) {
this.arr = arr
}
init () {
const fragment = document.createDocumentFragment()
for (let i = 0; i < this.arr.length; i++) {
const li = document.createElement('li')
li.textContent = this.arr[i]
fragment.appendChild(li)
}
list.appendChild(fragment)
}
addList (val) {
const li = document.createElement('li')
li.textContent = val
list.appendChild(li)
}
}
const todoList = new Proxy([], {
get (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
if (key !== 'length') {
render.addList(value)
}
return Reflect.set(target, key, value, receiver)
}
})
window.onload = () => {
render = new Render([])
render.init()
}
input.addEventListener('keyup', e => {
inputObj.text = e.target.value
})
btn.addEventListener('click', () => {
todoList.push(inputObj.text)
inputObj.text = ''
}) |
set(target, key, value, receiver)
禁止读写内部属性 const handler = {
get (target, key) {
invariant(key, 'get');
return target[key];
},
set (target, key, value) {
invariant(key, 'set');
target[key] = value;
return true;
}
};
function invariant (key, action) {
if (key[0] === '_') {
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
}
}
const target = {};
const proxy = new Proxy(target, handler);
proxy._prop
// Error: Invalid attempt to get private "_prop" property
proxy._prop = 'c'
// Error: Invalid attempt to set private "_prop" property
const handler = {
set: function(obj, prop, value, receiver) {
obj[prop] = receiver;
}
};
const proxy = new Proxy({}, handler);
const myObj = {};
// myObj 原型指向 proxy
Object.setPrototypeOf(myObj, proxy);
myObj.foo = 'bar';
myObj.foo === myObj // true 上面代码中,设置
|
apply(target, ctx, args)apply方法拦截函数的调用、call和apply操作。
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"
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 |
Proxy相比Object.defineProperty的优势
|
抱歉,会 Proxy 真的可以为所欲为。
The text was updated successfully, but these errors were encountered: