我想我会发布这篇文章,因为我在没有真正了解正在发生的事情的情况下通过猜测来完成工作,我认为如果有人解释它可能会有所帮助.
我理解如何在Compojure处理程序中获取:params map的元素:
(GET "/something" [some_arg] "this is the response body")
Run Code Online (Sandbox Code Playgroud)
要么
(GET "/something" {{some_arg "some_arg"} :params} "this is the response body")
Run Code Online (Sandbox Code Playgroud)
虽然我不完全明白这{some_arg "some_arg"}部分在做什么:(
我也想访问:remote-addr请求的一部分以及some_arg.我结束了
(GET "/something" {{some_arg "some_arg"} :params ip :remote-addr}
(do-something-with some_arg ip))
Run Code Online (Sandbox Code Playgroud)
所以,我得到了未加引号的字符串,some_arg并且ip是我想要绑定值的变量的名称,但上面的地图不是有效的Clojure映射.它是如何工作的?
我还得到这是根据Ring请求映射(由某种方式由defroutes宏提供)进行评估,但上面的表达式不是函数或宏定义,那么它如何在我的代码中"存在"为有效表达式?宏观参数的正常规则是否存在某种暂停?我一直无法找到这种非Lisp'er可理解的解构形式语法的定义.
我有一个Scala列表.我可以将列表解构为一些变量:
var a :: b :: tail = myList
a should be ("A1")
b should be ("B1")
tail should be ('empty)
Run Code Online (Sandbox Code Playgroud)
但是,我似乎无法将相同的变量重用于另一个解构:
a :: b :: tail = anotherList
a should be ("A2")
b should be ("B2")
tail should be ('empty)
Run Code Online (Sandbox Code Playgroud)
编译器告诉我,它期望一个分号,但发现了一个等号.为什么是这样?在解构时是不可能使用已经声明的变量?我做了些蠢事吗?
我正在尝试编写一个宏,它通过解构扩展为let形式.我的问题是我希望得到let表单中定义的符号列表,包括通过destruturing获得的符号.
用例
我试图将这种行为分解出来,例如验证:
(let [a (foo bar)
{x :x,
y :y,
{u :u, v: v :as nested-map} :nested} some-map]
(and x y nested-map u v ; testing truthiness
(valid-a? a)
(valid-x? x)
(valid-y? y)
(valid-nested? nested-map)
(valid-u-and-v? u v)
))
Run Code Online (Sandbox Code Playgroud)
提出的解决方案
通过某种类型的and-let宏来实现这一点真的很好,我可以像这样调用它:
(and-let [a (foo bar)
{x :x,
y :y,
{u :u, v: v :as nested-map} :nested} some-map]
(valid-a? a)
(valid-x? x)
(valid-nested? nested-map)
(valid-u-and-v? u v))
Run Code Online (Sandbox Code Playgroud)
我错过了什么
但是我错过了一些访问let表单中绑定的符号列表的方法.如果我有类似list-bound-symbols函数的东西,我可以这样做:
(defmacro and-let
"Expands to an AND close …Run Code Online (Sandbox Code Playgroud) 我想使用解构赋值交换元组的元素,如下所示:
var a = [1,2];
[a[1], a[0]] = a;
Run Code Online (Sandbox Code Playgroud)
但是,这会产生[1, 1].
Babel编译为
a[1] = a[0];
a[0] = a[1];
Run Code Online (Sandbox Code Playgroud)
我原以为这应该编译为
let tmp0 = a[0];
let tmp1 = a[1];
a[0] = tmp1;
a[1] = tmp0;
Run Code Online (Sandbox Code Playgroud)
Traceur的行为与babel完全相同.所以我猜这是指定的行为?
我想把两个元素交换到位.这是唯一的方法......
let tmp = a[0];
a[0] = a[1];
a[1] = tmp;
Run Code Online (Sandbox Code Playgroud)
但我认为以上是解构分配应该让我避免不得不这样做.
我完全有能力颠倒数组的两个元素的顺序,所以这不是我的问题.我可以做一些简单的事情a.push(a.shift()),它符合交换到位的标准.
我最感兴趣的是为什么解构不会像它应该的那样运作.
我在ES6中实现了一个简单的GCD算法(通过node-esml),并且在一个while循环中更新了变量值,从而产生了奇怪的行为.这段代码非常有用:
function gcdWithTemp(x, y) {
let [r, rdash] = [x, y]
while (r != 0) {
q = Math.floor(rdash / r)
temp = r
r = rdash - q * r
rdash = temp
}
return(rdash)
}
console.log(gcdWithTemp(97, 34))
Run Code Online (Sandbox Code Playgroud)
回到了预期的答案1.但是,如果我删除临时变量而是使用解构赋值来尝试实现相同的结果:
function gcdWithDestructuredAssignment(x, y) {
let [r, rdash] = [x, y]
while (r != 0) {
q = Math.floor(rdash / r)
[r, rdash] = [rdash - q * r, r]
}
return(rdash)
}
console.log(gcdWithDestructuredAssignment(97, 34))
Run Code Online (Sandbox Code Playgroud)
它永远不会完成,进一步调试显示r将始终具有分配给的第一个值,x.看来这两个实现应该是一样的吗?请参阅交换变量 …
我在一篇文章中遇到了这种解构表达.
const words = ['oops', 'gasp', 'shout', 'sun'];
let { length } = words;
console.log(length); // 4
Run Code Online (Sandbox Code Playgroud)
如何length获得4的值?我知道.length是数组的属性,但这种语法是如何工作的?它似乎正在做let length = words.length;,事实上在babel确实输出它.但我的问题是它背后的逻辑是什么?令我困惑的是一系列价值观的混合和使用{length}.
我已经阅读了MDN的描述,但无法看到这个例子的解释.
在 python 中,我可以传递一个字典,其键与参数名称与**(double-splat) 运算符匹配:
def foo(a, b):
print (a - b)
args = {'b': 7, 'a': 10}
foo(**args) # prints 3
Run Code Online (Sandbox Code Playgroud)
在 ES6 中如何做同样的事情?这不起作用:
def foo(a, b):
print (a - b)
args = {'b': 7, 'a': 10}
foo(**args) # prints 3
Run Code Online (Sandbox Code Playgroud)
注意:我正在寻找一种不涉及更改签名的解决方案,foo因为我希望它以任何方式使用(带或不带解构)。所以以下应该有效:
foo(<magic>args);
foo(123, 456);
Run Code Online (Sandbox Code Playgroud)
额外问题:为什么错误消息是“未定义不是函数”?这里到底什么是未定义的?
(正如 @Nina Scholz 在评论中回答的那样,这是因为...要求其参数具有Symbol.iterator,而这不是为对象定义的)。
在JavaScript中解构对象时如何绑定方法?
const person = {
getName: function() {
console.log(this);
}
};
var a = person.getName;
var b = person.getName.bind(person);
var {getName: c} = person;
person.getName(); //=> {getName: [Function]}
a(); //=> window or global
b(); //=> {getName: [Function]}
c(); //=> window or global
Run Code Online (Sandbox Code Playgroud)
我要c在控制台中登录其“父”对象{getName:
[Function]}。
在一条销毁线中销毁一个对象时,有什么方法可以绑定所有方法?
我正在尝试使用destructuring来使用命名函数参数和默认值.
function doSomething({arg1 = "foo", arg2 = "bar"} = {}) {
console.log(arg1, arg2);
}
Run Code Online (Sandbox Code Playgroud)
但我也想访问整个对象,以防用户添加一些额外的字段.这实际上不起作用,但我正在拍摄这样的事情:
function doSomething(parameters = {arg1 = "foo", arg2 = "bar"} = {}) {
console.log(arg1, arg2, parameters);
// parameters should contain arg1 and arg2, plus any additional user supplied keys.
}
Run Code Online (Sandbox Code Playgroud)
有没有一种优雅的方法来使用解构来做到这一点?(我尝试过使用arguments[0]但实际上并没有包含我的默认值arg1,和arg2.)
谢谢.
我想用函数组件中的单个更改处理程序来更新表单中的几个值的状态。我不知道如何以正确的方式设置该州的单个属性。我已经在类组件中看到了它的工作原理。
import React, {useState} from 'react'
import ReactDOM from 'react-dom'
export function Example(){
const [user, setUser] = useState({nickname: '', age: 0})
const handleChange = event => {
const { name, value } = event.target
setUser({ [name]: value })
}
return(
<form>
<input name="nickname" onChange={handleChange} />
<input name="age" onChange={handleChange} />
<button onClick={(e) => {
e.preventDefault()
console.log(user)
}}>Show User</button>
</form>
)
}
ReactDOM.render(
<Example />,
document.getElementById('app')
);
Run Code Online (Sandbox Code Playgroud)
上面的代码不能按我想要的方式工作,因为它总是覆盖整个状态,而不仅仅是相应的属性。
我收到:
Object {age: "24"}
Object {nickname: "Lala"}
Run Code Online (Sandbox Code Playgroud)
我想:
Object {age: "24", nickname: "Lala"}
Run Code Online (Sandbox Code Playgroud)
实现这一目标的最佳实践是什么?
destructuring ×10
javascript ×7
ecmascript-6 ×4
clojure ×2
arrays ×1
compojure ×1
double-splat ×1
macros ×1
node.js ×1
reactjs ×1
scala ×1
state ×1
swap ×1
this ×1