为什么eren' t函数作为可变形的参数传递,例如JS中的其他对象(对象,数组)?
例如,我们知道,如果对数组的引用在函数范围内被突变或重新分配,则该数据的任何指针也将指向突变/重新分配的值。
function arrReassigned() {
let arr = [1,2,3];
setTimeout(() => console.log(arr), 0);
arr = [4,5,6];
}
function arrMutates() {
const arr = [1,2,3];
setTimeout(() => console.log(arr), 0);
arr.push(4);
}
let nums = [1,2,3];
function mutateNums(nums) {
nums.push(4);
}
arrReassigned(); // [4,5,6]
arrMutates(); // [1,2,3,4]
mutateNums(nums);
console.log(nums); // [1,2,3,4]
我对上述内容的理解是:
arr
最初是分配的- settimeout,并立即弹出呼叫堆栈,回调arg被推入JS任务队列〜0毫秒〜0毫秒后,
- 对数组的引用被重新分配或值得重新分配的值它指出要进行突变的
- 呼叫堆栈是空的,因此事件循环将任务队列的回调推到呼叫堆栈上。回调执行和引用按预期重新分配/突变的ARR变量。
我试图通过功能重新分配来重新创建此功能,但它的行为不像预期。
function a() {
function b() { console.log('b') }
setTimeout(b, 0);
b = function() { console.log('c') }
b();
}
a(); // logs 'c' then 'b'
当功能b
以参数传递并最终通过任务队列调用时,它不会引用重新分配的值。
function a() {
function b() { console.log('b') }
setTimeout(() => b(), 0);
b = function() { console.log('c') }
b();
}
a(); // logs 'c' then 'c'
当我们将一个Anon回调传递到SetteMeout中时,它似乎会按照我们的期望引用重新分配的函数。
到底发生了什么?如果该函数是作为参数传递的,为什么它不像另一个对象那样引用重新分配的值(例如数组)。我的理解是,当Settimeout执行执行时,创建了对函数的引用的副本,但是当当将其引用的副本作为参数传递到函数和函数时,我为何不遵循其他对象的规则感到困惑然后可以突变。
For example, we know that if a reference to an array gets mutated or reassigned within the scope of a function, any pointers to that data will also point to the mutated/reassigned value.
function arrReassigned() {
let arr = [1,2,3];
setTimeout(() => console.log(arr), 0);
arr = [4,5,6];
}
function arrMutates() {
const arr = [1,2,3];
setTimeout(() => console.log(arr), 0);
arr.push(4);
}
let nums = [1,2,3];
function mutateNums(nums) {
nums.push(4);
}
arrReassigned(); // [4,5,6]
arrMutates(); // [1,2,3,4]
mutateNums(nums);
console.log(nums); // [1,2,3,4]
My understanding of the above:
arr
is initially assigned- setTimeout is pushed and immediately popped off call stack, callback arg gets pushed into JS task queue after ~0 milliseconds
- The reference to the array gets reassigned or the value that it points to gets mutated
- Call stack is empty, so event loop pushes the callback from the task queue onto the call stack. Callback executes and references the reassigned/mutated arr variable as expected.
I tried to recreate this with function reassignment, but it doesn't behave as expected.
function a() {
function b() { console.log('b') }
setTimeout(b, 0);
b = function() { console.log('c') }
b();
}
a(); // logs 'c' then 'b'
When function b
is passed in as an argument and eventually called via the task queue, it doesn't reference the reassigned value.
function a() {
function b() { console.log('b') }
setTimeout(() => b(), 0);
b = function() { console.log('c') }
b();
}
a(); // logs 'c' then 'c'
When we pass an anon callback into setTimeout instead, it seems to reference the reassigned function as we would expect.
What exactly is going on here? If the function is passed as an argument, why does it not reference the reassigned value like another object would (e.g. arrays). My understanding is that a copy of the reference to the function is created when setTimeout executes, but I'm confused as to why it doesn't follow the rules of other objects when a copy of their reference is passed as arguments into a function and can then be mutated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
重要的是,当变量被查找以获取其价值时。如果您在回调函数中查找变量,则在重新分配后将获得其最新值。
当您进行
settimeout(b,0)
时,b
在调用settimeout()
时查找。获取原始函数对象,然后将其传递给settimeout()
。重新分配变量对此没有影响。当您执行
settimeout(()=> b(),0)
时,您将匿名函数传递到settimeout()
。调用该功能时,它会查找b
并获取其更新值。What matters is when the variable is looked up to get its value. If you look up the variable in the callback function, it will get its latest value, after the reassignment.
When you do
setTimeout(b, 0)
,b
is looked up at the time you callsetTimeout()
. That gets the original function object, and passes that tosetTimeout()
. Reassigning the variable has no effect on this.When you do
setTimeout(() => b(), 0)
, you're passing the anonymous function tosetTimeout()
. When that function is called, it looks upb
and gets its updated value.因为您没有做同样的事情。在您的
arrReassigned
函数中,您将功能传递到settimeout
上,该功能通过arr
关闭。当该功能运行时,它会看到arr
的当时流动值。但是在您的第一个
a
函数中,您将b
本身本身传递到settimeout
中。然后,您将b
分配一个新值,但这对将您传递到settimeout
的值没有任何影响。如果使
与
arrreassigned
相同,则通过通过关闭b
的函数,您会看到您期望的结果:在这方面,如何处理函数对象和数组对象(或任何其他类型的对象)没有区别。例如,以相反的方式进行此操作,使
arrReassigned
看不到重新分配,因为您的第一个a
没有:这与您的第一个
a
函数完全一样示例
logs[1,2,3]
。您似乎特别有疑问的部分是(第一个
a
):a ()的情况
让我们浏览您调用
将对该功能的引用分配给本地变量
b
。在这一点上,我们在内存中有类似的东西:“ Ref54612”只是代表性的,但是(无论如何对我来说)将对象引用视为数字,这些数字告诉javaScript引擎,在内存中对象在其他位置的位置。
2。它调用
settimeout(b,0);
将b
的当前值传递到settimeut
中,这将其放在记录中环境的计时器列表说“在x时呼唤这个”。在这一点上,我们在内存中有类似的东西:3。它为
b
变量分配了 new 函数。现在我们有了这样的东西:请注意如何更改
b
内部的值(“ ref84965”)对计时器要调用的功能没有任何影响(“ ref54612”)。4。它调用
b()
,该记录c
,因为这是新函数所做的。5。后来,当主机环境看到该函数是时候在Ref54612上调用该函数时,它确实可以记录“ B”,因为那是该函数的作用。
相反,使用您的
arrReassigned
示例,您将函数(不是arr
)传递给settimeout
(因为传递arr
对于它是没有意义的),后来在运行函数时会查找arr
然后的值,并使用了您分配给它的新数组。Because you're not doing the same thing. In your
arrReassigned
function, you're passing a function intosetTimeout
that closes overarr
. When that function runs, it sees the then-current value ofarr
.But in your first
a
function, you're passingb
itself intosetTimeout
. Then you assignb
a new value, but that has no effect whatsoever on the value you passed intosetTimeout
.If you make
a
the same asarrReassigned
by passing in a function that closes overb
, you see the result you expect:There is no difference in how function objects and array objects (or any other kind of object) are handled in this regard. For instance, here's things going the other way, making
arrReassigned
not see the reassignment for the same reason your firsta
didn't:That's exactly like your first
a
function: It passes the object reference intoexample
, then changes the variable that came from, which has no effect on what was passed in earlier, soexample
logs[1, 2, 3]
.The part you seem particularly to have questions about is this (the first
a
):Let's walk through what happens when you call
a
():1. It creates a function and assigns a reference to that function to the local variable
b
. At this point, we have something like this in memory:The "Ref54612" is just representative, but it's useful (to me, anyway) to think of object references as numbers that tell the JavaScript engine where the object is elsewhere in memory.
2. It calls
setTimeout(b, 0);
That passes the current value ofb
intosetTimeout
, which puts that in a record in the timers list of the environment saying "call this at X time". At this point, we have something like this in memory:3. It assigns a new function to the
b
variable. Now we have something like this:Notice how changing the value inside
b
(to "Ref84965") had no effect whatsoever on what function the timer is going to call ("Ref54612").4. It calls
b()
, which logsc
since that's what the new function does.5. Later, when the host environment sees that it's time to call the function at Ref54612, it does — logging "b", since that's what that function does.
In contrasts, with your
arrReassigned
example, you passed a function (notarr
) tosetTimeout
(since passingarr
to it wouldn't make sense), and later when the function was run it looked up the value ofarr
then, and used the new array you'd assigned to it.