sam*_*ime 8 javascript ecmascript-6 babeljs ecmascript-7 ecmascript-next
有没有更清洁的方法来做到这一点(任何至少是ES草案并有一个babel插件,即ES6,ES7等):
const { a, b } = result = doSomething();
Run Code Online (Sandbox Code Playgroud)
我希望将整体结果保持为一个单一对象,同时也将其结构化.它在技术上有效,但result
隐式声明(带隐式var
),而我真的希望它也是一个const.
我现在正在这样做:
const result = doSomething();
const { a, b } = result;
Run Code Online (Sandbox Code Playgroud)
这再次起作用,但它略显冗长,因为我需要重复这种模式数十次.
理想情况下,我想要的是:
const { a, b } = const result = doSomething();
Run Code Online (Sandbox Code Playgroud)
但这显然是无效的语法.
rai*_*7ow 10
一种可能的方式:
const result = doSomething(),
{ a, b } = result;
Run Code Online (Sandbox Code Playgroud)
但是,您仍然需要复制名称.const
令牌不是很方便.)
创建这个辅助函数:
function use(input, callback) {
callback(input, input);
}
Run Code Online (Sandbox Code Playgroud)
并使用它像:
use(doSomething(), (result, {a, b}) => {
// Do something with result as a whole, or a and b as destructured properties.
});
Run Code Online (Sandbox Code Playgroud)
例如:
use ({a: "Hello", b: "World", c: "!"}, (result, {a, b}) => {
console.log(result);
console.log(a);
console.log(b);
});
// generates
// {a: "Hello", b: "World", c: "!"}
// Hello
// World
Run Code Online (Sandbox Code Playgroud)
他们不是
const
,但他们的范围,无论好坏!
结合array
和object
解构.创建这个辅助函数:
const dup = input => [input, input];
Run Code Online (Sandbox Code Playgroud)
然后像这样解构:
const [result, {a, b}] = dup(doSomething());
Run Code Online (Sandbox Code Playgroud)
现在,你
result
,a
和b
都是const
秒.
在 @raina77ow 的回答中,他们感叹;但如果您使用冒号(并重复关键字)而不是逗号,这就是您的答案。\n但是你已经在问题中提到了,我不认为它有什么更糟的地方,而且它有效。const
token isn\'t quite right-handy
const result = doSomething(); const {a, b} = result;
但从中你可以看到的一件事是,它let something = x; let another = y;
与 相同let [something, another] = [x, y];
。
\n因此,一个真正优雅的解决方案实际上很简单:
const [result, {a, b}] = [,,].fill(doSomething());\n
Run Code Online (Sandbox Code Playgroud)\n\n你需要额外的,,
因为它是尾随的
除此之外(使其成为自己的答案,而不仅仅是值得评论的) ,这种复制也可以在解构语法中完成(这就是我遇到这个问题的原因)。
\n假设其b
内部result
有一个c
; 你想要解构它,但也要保留对 的引用b
。
//The above might lead you to believe you need to do this:\nconst result = doSomething(); const {a, b} = result; const {c} = b;\n//or this\nconst [result, {a, b}, {b:{c}}] = [,,,].fill(doSomething());\n
Run Code Online (Sandbox Code Playgroud)\n\n但你实际上可以
\n\nconst [result, {a, b, b:{c}}] = [,,].fill(doSomething());\n
Run Code Online (Sandbox Code Playgroud)\n\n现在你有result
, a
, b
, & c
,即使 a & b 在结果中,而 c 在 b 中。
\n如果您实际上不需要result
,这尤其方便,看起来fill()
只需要根对象:
\nconst {a, b, b:{c}} = doSomething();
这似乎不适用于数组,因为语法中的位置是关键
\n\nconst [result, [a, b, /*oops, I\'m referencing index 2 now*/]] = [,,].fill(doArrayThing());\n
Run Code Online (Sandbox Code Playgroud)\n\n但是,数组是对象,因此您可以仅使用索引作为键并欺骗索引引用:
\n\nconst [result, {0:a, 1:b, 1:{c}}] = [,,].fill(doArrayThing());\n
Run Code Online (Sandbox Code Playgroud)\n\n这也意味着您可以解构类似数组的结构,而通常它会抱怨对象不可迭代,并且您可以通过使用更高的键而不是必须编写空逗号的数组语法来跳过索引。
\n也许最好的一点是,{0:a, 1:b, ...c}
仍然可以正常工作[a, b, ...c]
,因为Object.keys()
for 数组会拉取其索引(但结果c
不会有.length
)。
但我对此并不满足,而且我真的很喜欢@Arash 的想法#2,但它不够通用,无法帮助消除b
上面示例中的重复内容,而且它会欺骗这些const
行。
所以...我自己写了:| (ctrl+F for goodluck
)
\n您使用相同的正常语法,但有一些例外:
[,,] = input
变为`[,,] = ${input}`
[a, b, ...c] = input
变成`[, , ...] ${input}`
\xce\xbc
(您可以将其命名为任何名称)是您指定的元素的数组,以便const {a:A, b:B} = input;
成为const [A,B] = \xce\xbc`{a, b} ${input}`;
const [a, , , d] = input;
isconst [a,d] = \xce\xbc`[ , 2, ]`;
例如
\n\nconst [result, {a, b, b:{c}}] = [,,].fill(doSomething());\n
Run Code Online (Sandbox Code Playgroud)\n\n变成
\n\nconst [result, a, b] = \xce\xbc`:{a, b::{c}} ${doSomething()}`;\n
Run Code Online (Sandbox Code Playgroud)\n\n因此,除了上述优点之外,还有以下优点:
\n\n例如,ES6 甚至不关心这个:
\n\n_ = {a:7, get b() {throw \'hi\'}};\nconsole.warn(\'ES6\');\nout(() => {\n const {a, b} = _;\n return [a, b];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const {a,b} = \xce\xbc`{a,...} ${_}`;\n return [a, b];\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n\n\nEg2 这里 ES6 说_
是罪魁祸首。我不仅正确地说它有1
错误,而且我告诉你它在解构中发生的位置:
_ = [1];\nconsole.warn(\'ES6\');\nout(() => {\n const [[a]] = _;\n return [a];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const [a] = \xce\xbc`[[]] ${_}`;\n return [a];\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n\n\n例如
\n\nconst [[a,,,,,,,,,j], [[aa, ab], [ba]]] = [,,].fill(_);\nconst [a, aa, ab, ba, j] = \xce\xbc`[:[ , ], [ ], 7, ] ${_}`;\n
Run Code Online (Sandbox Code Playgroud)\n\n好吧,有什么问题吗?缺点:
\n\nconst [
发生在其外部。.d.ts
)如果您正在使用某种类型检查例如
\n\n_ = [1, 2, 3, 4];\nconsole.warn(\'ES6\');\nout(() => {\n eval(`const [a, ...betwixt, b] = _`);\n return [a, betwixt, b];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const [a, betwixt, b] = \xce\xbc`[, ..., ] ${_}`;\n return [a, betwixt, b];\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n\n\n:{
:[
如果和被采用到语言中,这将与第 1 点一起修复[2
,您不需要在您的外部重新指定const [
window.\xce\xbc = (() => {\n //build regexes without worrying about\n // - double-backslashing\n // - adding whitespace for readability\n // - adding in comments\n let clean = (piece) => (piece\n .replace(/(?<=^|\\n)(?<line>(?:[^\\/\\\\]|\\/[^*\\/]|\\\\.)*)\\/\\*(?:[^*]|\\*[^\\/])*(\\*\\/|)/g, \'$<line>\')\n .replace(/(?<=^|\\n)(?<line>(?:[^\\/\\\\]|\\/[^\\/]|\\\\.)*)\\/\\/[^\\n]*/g, \'$<line>\')\n .replace(/\\n\\s*/g, \'\')\n );\n let regex = ({raw}, ...interpolations) => (\n new RegExp(interpolations.reduce(\n (regex, insert, index) => (regex + insert + clean(raw[index + 1])),\n clean(raw[0])\n ))\n );\n\n let start = {\n parse : regex`^\\s*(?:\n //the end of the string\n //I permit the equal sign or just declaring the input after the destructure definition without one\n (?<done>=?\\s*)\n |\n //save self to output?\n (?<read>(?<save>:\\s*|))\n //opening either object or array\n (?<next>(?<open>[{[]).*)\n )$`\n };\n let object = {\n parse : regex`^\\s*\n (?<read>\n //closing the object\n (?<close>\\})|\n\n //starting from open or comma you can...\n (?:[,{]\\s*)(?:\n //have a rest operator\n (?<rest>\\.\\.\\.)\n |\n //have a property key\n (?<key>\n //a non-negative integer\n \\b\\d+\\b\n |\n //any unencapsulated string of the following\n \\b[A-Za-z$_][\\w$]*\\b\n |\n //a quoted string\n (?<quoted>"|\')(?:\n //that contains any non-escape, non-quote character\n (?!\\k<quoted>|\\\\).\n |\n //or any escape sequence\n (?:\\\\.)\n //finished by the quote\n )*\\k<quoted>\n )\n //after a property key, we can go inside\n \\s*(?<inside>:|)\n )\n )\n (?<next>(?:\n //after closing we expect either\n // - the parent\'s comma/close,\n // - or the end of the string\n (?<=\\})\\s*(?:[,}\\]=]|$)\n |\n //after the rest operator we expect the close\n (?<=\\.)\\s*\\}\n |\n //after diving into a key we expect that object to open\n (?<=:)\\s*[{[:]\n |\n //otherwise we saw only a key, we now expect a comma or close\n (?<=[^:\\.}])\\s*[,}]\n ).*)\n $`,\n //for object, pull all keys we havent used\n rest : (obj, keys) => (\n Object.keys(obj)\n .filter((key) => (!keys[key]))\n .reduce((output, key) => {\n output[key] = obj[key];\n return output;\n }, {})\n )\n };\n let array = {\n parse : regex`^\\s*\n (?<read>\n //closing the array\n (?<close>\\])\n |\n //starting from open or comma you can...\n (?:[,[]\\s*)(?:\n //have a rest operator\n (?<rest>\\.\\.\\.)\n |\n //skip some items using a positive integer\n (?<skip>\\b[1-9]\\d*\\b)\n |\n //or just consume an item\n (?=[^.\\d])\n )\n )\n (?<next>(?:\n //after closing we expect either\n // - the parent\'s comma/close,\n // - or the end of the string\n (?<=\\])\\s*(?:[,}\\]=]|$)\n |\n //after the rest operator we expect the close\n (?<=\\.)\\s*\\]\n |\n //after a skip we expect a comma\n (?<=\\d)\\s*,\n |\n //going into an object\n (?<=[,[])\\s*(?<inside>[:{[])\n |\n //if we just opened we expect to consume or consume one and close\n (?<=\\[)\\s*[,\\]]\n |\n //otherwise we\'re just consuming an item, we expect a comma or close\n (?<=[,[])\\s*[,\\]]\n ).*)\n $`,\n //for \'array\', juice the iterator\n rest : (obj, keys) => (Array.from(keys))\n };\n\n let destructure = ({next, input, used}) => {\n//for exception handling\nlet phrase = \'\';\nlet debugging = () => {\n let tmp = type;\n switch (tmp) {\n case object: tmp = \'object\'; break;\n case array : tmp = \'array\'; break;\n case start : tmp = \'start\'; break;\n }\n console.warn(\n `${tmp}\\t%c${phrase}%c\\u2771%c${next}`,\n \'font-family:"Lucida Console";\',\n \'font-family:"Lucida Console";background:yellow;color:black;\',\n \'font-family:"Lucida Console";\',\n//input, used\n );\n};\ndebugging = null;\n //this algorithm used to be recursive and beautiful, I swear,\n //but I unwrapped it into the following monsterous (but efficient) loop.\n //\n //Lots of array destructuring and it was really easy to follow the different parse paths,\n //now it\'s using much more efficient `[].pop()`ing.\n //\n //One thing that did get much nicer with this change was the error handling.\n //having the catch() rethrow and add snippets to the string as it bubbled back out was...gross, really\n let read, quoted, key, save, open, inside, close, done, rest, type, keys, parents, stack, obj, skip;\ntry {\n let output = [];\n while (\n //this is the input object and any in the stack prior\n [obj, ...parents] = input,\n //this is the map of used keys used for the rest operator\n [keys, ...stack] = used,\n //assess the type from how we are storing the used \'keys\'\n type = (!keys) ? start : (typeof keys.next == \'function\') ? array : object,\nphrase += (read || \'\'),\nread = \'\',\ndebugging && debugging(),\n //parse the phrase, deliberately dont check if it doesnt match; this way it will throw\n {read, quoted, next, key, save, open, inside, close, done, rest, skip} = next.match(type.parse).groups,\n done == null\n ) {\n if (open) {\n //THIS IS THE EXTRA FUNCTIONALITY\n if (save)\n output.push(obj);\n switch (open) {\n case \'{\':\n used = [{}, ...stack];\n break;\n case \'[\':\n used = [obj[Symbol.iterator](), ...stack];\n input = [null, ...parents];\n break;\n default:\n throw open;\n }\n continue;\n }\n\n if (close) {\n used = stack;\n input = parents;\n continue;\n }\n //THIS IS THE EXTRA FUNCTIONALITY\n if (skip) {\n for (skip = parseInt(skip); skip-- > 0; keys.next());\n continue;\n }\n\n //rest operator\n if (rest) {\n obj = type.rest(obj, keys);\n //anticipate an immediate close\n input = [null, ...parents];\n }\n //fetch the named item\n else if (key) {\n if (quoted) {\n key = JSON.parse(key);\n }\n keys[key] = true;\n obj = obj[key];\n }\n //fetch the next item\n else\n obj = keys.next().value;\n\n //dive into the named object or append it to the output\n if (inside) {\n input = [obj, ...input];\n used = [null, ...used];\n }\n else\n output.push(obj);\n }\n return output;\n}\ncatch (e) {\n console.error(\'%c\\u26A0 %cError destructuring\', \'color:yellow;\', \'\', ...input);\n console.error(\n `%c\\u26A0 %c${phrase}%c${read || \'\\u2771\'}%c${next || \'\'}`,\n \'color:yellow;\',\n \'font-family:"Lucida Console";\',\n \'font-family:"Lucida Console";background:red;color:white;\',\n \'font-family:"Lucida Console";\'\n );\n throw e;\n}\nreturn null;\n };\n //just to rearrange the inputs from template literal tags to what destructure() expects.\n //I used to have the function exposed directly but once I started supporting\n //iterators and spread I had multiple stacks to maintain and it got messy.\n //Now that it\'s wrapped it runs iteratively instead of recursively.\n return ({raw:[next]}, ...input) => (destructure({next, input, used:[]}));\n})();\n
Run Code Online (Sandbox Code Playgroud)\n\n演示的测试:
\n\nlet out = (func) => {\n try {\n console.log(...func().map((arg) => (JSON.stringify(arg))));\n }\n catch (e) {\n console.error(e);\n }\n};\nlet _;\n\n//THE FOLLOWING WORK (AND ARE MEANT TO)\n_ = {a:{aa:7}, b:8};\nout(() => {\n const [input,{a,a:{aa},b}] = [,,].fill(_);\n return [input, a, b, aa];\n});\nout(() => {\n const [input,a,aa,b] = \xce\xbc`:{a::{aa},b}=${_}`;\n return [input, a, b, aa];\n});\n\n_ = [[65, -4], 100, [3, 5]];\nout(() => {\n //const [[aa, ab], , c] = input; const [ca, cb] = c;\n const {0:{0:aa, 1:ab}, 2:c, 2:{0:ca, 1:cb}} = _;\n return [aa, ab, c, ca, cb];\n});\nout(() => {\n const [aa,ab,c,ca,cb] = \xce\xbc`{0:{0,1}, 2::{0,1}}=${_}`;\n return [aa, ab, c, ca, cb];\n});\n\n_ = {a:{aa:7, ab:[7.5, 7.6, 7.7], \'a c"\\\'\':7.8}, b:8};\nout(() => {\n const [input,{a,a:{aa,ab,ab:{0:aba, ...abb},"a c\\"\'":ac},b,def=\'hi\'}] = [,,].fill(_);\n return [input, a, aa, ab, aba, abb, ac, b, def];\n});\nout(() => {\n const [input,a,aa,ab,aba,abb,ac,b,def=\'hi\'] = \xce\xbc`:{a::{aa,ab::{0, ...},"a c\\"\'"},b}=${_}`;\n return [input, a, aa, ab, aba, abb, ac, b, def];\n});\n\n_ = [{aa:7, ab:[7.5, {abba:7.6}, 7.7], \'a c"\\\'\':7.8}, 8];\nout(() => {\n const [input,[{aa,ab,ab:[aba,{abba},...abc],"a c\\"\'":ac}],[a,b,def=\'hi\']] = [,,,].fill(_);\n return [input, a, aa, ab, aba, abba, abc, ac, b, def];\n});\nout(() => {\n const [input,a,aa,ab,aba,abba,abc,ac,b,def=\'hi\'] = \xce\xbc`:[:{aa,ab::[,{abba},...],"a c\\"\'"},]=${_}`;\n return [input, a, aa, ab, aba, abba, abc, ac, b, def];\n});\n\n_ = [[-1,-2],[-3,-4],4,5,6,7,8,9,0,10];\nout(() => {\n const [[a,,,,,,,,,j], [[aa, ab], [ba]]] = [,,].fill(_);\n return [a, aa, ab, ba, j];\n});\nout(() => {\n const [a, aa, ab, ba, j] = \xce\xbc`[:[ , ], [ ], 7, ] ${_}`;\n return [a, aa, ab, ba, j];\n});\n\n\n//THE FOLLOWING FAIL (AND ARE MEANT TO)\n\n_ = [1];\nconsole.warn(\'ES6\');\nout(() => {\n const [[a]] = _;\n return [a];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const [a] = \xce\xbc`[[]] ${_}`;\n return [a];\n});\n\n\n_ = [1, 2, 3, 4];\nconsole.warn(\'ES6\');\nout(() => {\n eval(`const [a, ...betwixt, b] = _`);\n return [a, betwixt, b];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const [a, betwixt, b] = \xce\xbc`[, ..., ] ${_}`;\n return [a, betwixt, b];\n});\n\n\n_ = {a:7, get b() {throw \'hi\'}};\nconsole.warn(\'ES6\');\nout(() => {\n const {a, b} = _;\n return [a, b];\n});\nconsole.warn(\'hashbrown\');\nout(() => {\n const {a,b} = \xce\xbc`{a,...} ${_}`;\n return [a, b];\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n如果您的浏览器无法运行它但您很好奇,则输出(错误正在测试本机与此东西的错误输出)
\n\n\n 归档时间: |
|
查看次数: |
1443 次 |
最近记录: |