Spa*_*ner 7 javascript method-chaining
我认为我在方法链接方面缺少一些东西。对我来说感觉不完整。
方法链的工作原理是让每个方法返回this,以便可以调用该对象上的另一个方法。然而,返回值是this函数的结果而不是函数的结果这一事实对我来说似乎很不方便。
这是一个简单的例子。
const Obj = {
result: 0,
addNumber: function (a, b) {
this.result = a + b;
return this;
},
multiplyNumber: function (a) {
this.result = this.result * a;
return this;
},
}
const operation = Obj.addNumber(10, 20).multiplyNumber(10).result
console.log(operation)
Run Code Online (Sandbox Code Playgroud)
关键点:
Obj.addNumber(10, 20).multiplyNumber(10)都会返回this。.result是返回 以外的值的部分this。这种方法的问题在于,它需要您附加一个属性/方法才能在末尾获取除 之外的值this。
将其与 JavaScript 中的内置函数进行比较。
const str = " SomE RandoM StRIng "
console.log(str.toUpperCase()) // " SOME RANDOM STRING "
console.log(str.toUpperCase().trim()) // "SOME RANDOM STRING"
console.log(str.toUpperCase().trim().length) // 18
Run Code Online (Sandbox Code Playgroud)
关键点:
this(也许这是在幕后完成的)我们可以实现方法链来像 Javascript 中内置函数一样运行吗?
您可以使用带有-trap的Proxy 对象来避免隐式返回值的必要性this 并能够隐式返回值。get
在这里你可以找到一个更通用的工厂。
const log = Logger();
log(`<code>myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)</code> => ${
myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)}`,
);
log(`\n<code>myString(\`hello world\`)
.upper()
.trim()
.insertAt(6, \`cruel coding \`)
.upper()</code> => ${
myString(`hello world`)
.upper()
.trim()
.insertAt(6, `cruel coding `)
.upper()
}`);
log(`<br><code>myString(\`border-top-left-radius\`).toUndashed()</code> => ${
myString(`border-top-left-radius`).toUndashed()}`);
// the proxy handling
function proxyHandlerFactory() {
return {
get: (target, prop) => {
if (prop && target[prop]) {
return target[prop];
}
return target.valueOf;
}
};
}
// a wrapped string with chainable methods
function myString(str = ``) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
trim: () => nwProxy(str.trim()),
upper: () => nwProxy(str.toUpperCase()),
lower: () => nwProxy(str.toLowerCase()),
insertAt: (at, insertStr) =>
nwProxy(str.slice(0, at) + insertStr + str.slice(at)),
toDashed: () =>
nwProxy(str.replace(/[A-Z]/g, a => `-${a.toLowerCase()}`.toLowerCase())),
toUndashed: () => nwProxy([...str.toLowerCase()]
.reduce((acc, v) => {
const isDash = v === `-`;
acc = { ...acc,
s: acc.s.concat(isDash ? `` : acc.nextUpcase ? v.toUpperCase() : v)
};
acc.nextUpcase = isDash;
return acc;
}, {
s: '',
nextUpcase: false
}).s),
valueOf: () => str,
};
function nwProxy(nwStr) {
str = nwStr || str;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// a wrapped number with chainable methods
function myNum(n = 1) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
add: x => nwProxy(n + x),
divide: x => nwProxy(n / x),
multiply: x => nwProxy(n * x),
roundDown: () => nwProxy(Math.floor(n)),
roundUp: () => nwProxy(Math.ceil(n)),
valueOf: () => n,
};
function nwProxy(nwN) {
n = nwN || n;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// ---- for demo ---- //
function Logger() {
const report =
document.querySelector("#report") ||
document.body.insertAdjacentElement(
"beforeend",
Object.assign(document.createElement("pre"), {
id: "report"
})
);
return (...args) => {
if (!args.length) {
return report.textContent = ``;
}
args.forEach(arg =>
report.insertAdjacentHTML(`beforeEnd`,
`<div>${arg.replace(/\n/g, `<br>`)}</div>`)
);
};
}Run Code Online (Sandbox Code Playgroud)
body {
font: 12px/15px verdana, arial;
margin: 0.6rem;
}
code {
color: green;
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2344 次 |
| 最近记录: |