javascript - 为什么默认参数在 javascript 中的函数内部是不可变的?
问题描述
为什么,在 javascript 中,默认参数不能在函数内部更改,而非默认参数可以?
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // prints 99
对比
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // prints 10
解决方案
查看MDN 网络文档:
仅传递简单参数的非严格函数(即,不传递参数、默认参数或重组参数)会将函数体中的变量新值与参数对象同步,反之亦然:
function func(a) {
arguments[0] = 99; // updating arguments[0] also updates a
console.log(a);
}
func(10); // 99
并且
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // 99
相反,传递rest、默认或解构参数的非严格函数不会将分配给函数体中参数变量的新值与参数对象同步。相反,具有复杂参数的非严格函数中的 arguments 对象将始终反映在调用函数时传递给函数的值(这与所有严格模式函数表现出的行为相同,无论它们是什么类型的变量通过):
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // 10
和
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
并且
// An untracked default parameter
function func(a = 55) {
console.log(arguments[0]);
}
func(); // undefined
这可能是由于 javascript 编译器中的同步过程语法糖存在一些问题。
更新:
事实证明,deno
在这两种情况下都在做一些不同的事情和打印,这10
有点奇怪,所以我查看了这里生成的程序集:
deno eval 'function f(a) { a = 99; console.log(arguments[0]); } f(10);' --v8-flags='--print-bytecode,--print-bytecode-filter=f'
deno eval 'function f(a = 55) { arguments[0] = 99; console.log(a); } f(10);' --v8-flags='--print-bytecode,--print-bytecode-filter=f'
第一个命令打印我试图理解的这段代码,并在我认为它正在做相关事情的地方添加注释。
[generated bytecode for function: f (0x38db0826b679 <SharedFunctionInfo f>)]
Parameter count 2
Register count 4
Frame size 32
0x38db0826b846 @ 0 : 88 CreateUnmappedArguments
0x38db0826b847 @ 1 : 26 fb Star r0: Store accumulator in register 0 (presumibly function frame pointer)
0x38db0826b849 @ 3 : 0c 63 LdaSmi [99]: Load (SMallInteger) 99 in accumulator
0x38db0826b84b @ 5 : 26 02 Star a0: Store accumulator in function argument 0
0x38db0826b84d @ 7 : 13 00 00 LdaGlobal [0], [0]: I don't know
0x38db0826b850 @ 10 : 26 f9 Star r2: Store accumulator in register 2
0x38db0826b852 @ 12 : 28 f9 01 02 LdaNamedProperty r2, [1], [2]: Load a in the accumulator
0x38db0826b856 @ 16 : 26 fa Star r1: Store accumulator in register 1
0x38db0826b858 @ 18 : 0b LdaZero: Load 0 in accumulator
0x38db0826b859 @ 19 : 2a fb 04 LdaKeyedProperty r0, [4]: (presumibly) loading the property with key 4
from the function frame with the accumulator
(syncing) the argument here.
0x38db0826b85c @ 22 : 26 f8 Star r3: Store accumulator in register 3
0x38db0826b85e @ 24 : 59 fa f9 f8 06 CallProperty1 r1, r2, r3, [6]: console.log(r1)
0x38db0826b863 @ 29 : 0d LdaUndefined: Load undefined in accumulator
0x38db0826b864 @ 30 : aa Return: Return the accumulator value
Constant pool (size = 2)
Handler Table (size = 0)
Source Position Table (size = 0)
这是我处理的第二个程序的输出:
[generated bytecode for function: f (0x3bd80826b679 <SharedFunctionInfo f>)]
Parameter count 2
Register count 4
Frame size 32
0x3bd80826b846 @ 0 : 88 CreateUnmappedArguments
0x3bd80826b847 @ 1 : 26 fa Star r1: Store accumulator in register 1 (presumibly function frame pointer)
0x3bd80826b849 @ 3 : 25 02 Ldar a0: Load in the accumulator the argument 0
0x3bd80826b84b @ 5 : 9e 06 JumpIfNotUndefined [6] (0x3bd80826b851 @ 11): If accumulator is undefined:
0x3bd80826b84d @ 7 : 0c 37 LdaSmi [55]: Load (SMallInteger) 55 in accumulator
0x3bd80826b84f @ 9 : 8b 04 Jump [4] (0x3bd80826b853 @ 13): else:
0x3bd80826b851 @ 11 : 25 02 Ldar a0: Load argument 0 in accumulator
0x3bd80826b853 @ 13 : 26 fb Star r0: Store accumulator in register 0
0x3bd80826b855 @ 15 : 0b LdaZero: Load 0 in accumulator
0x3bd80826b856 @ 16 : 26 f8 Star r3: Store accumulator in register 3
0x3bd80826b858 @ 18 : 0c 63 LdaSmi [99]: Load (SMallInteger) 99 in accumulator
0x3bd80826b85a @ 20 : 30 fa f8 00 StaKeyedProperty r1, r3, [0]: (presumibly) loading in the function frame
(r1) the value of the accumulator (99) in the
property with key r3 (0) (syncing)
0x3bd80826b85e @ 24 : 13 00 02 LdaGlobal [0], [2]: (presumibly) loading the global value containing the
pointer to a in the accumulator
0x3bd80826b861 @ 27 : 26 f8 Star r3: Store accumulator in register 3
0x3bd80826b863 @ 29 : 28 f8 01 04 LdaNamedProperty r3, [1], [4]: Load a in the accumulator
0x3bd80826b867 @ 33 : 26 f9 Star r2: Store accumulator in register 2
0x3bd80826b869 @ 35 : 59 f9 f8 fb 06 CallProperty1 r2, r3, r0, [6]: console.log(r2)
0x3bd80826b86e @ 40 : 0d LdaUndefined: Load undefined in accumulator
0x3bd80826b86f @ 41 : aa Return: Return the accumulator value
Constant pool (size = 2)
Handler Table (size = 0)
Source Position Table (size = 0)
如您所见,第二个代码看起来像第一个,添加了一个 if 语句来检查可选参数。
最后,v8 google engine
insidedeno
打印10
了两次。这很奇怪,但我认为发生这种情况是有原因的。可能有人在他们的实施中做出了这个决定,并不是每个人都反映了这个变化。但是,请不要烤我,我尽力在没有手册的情况下理解字节码,所以如果有错误,请告诉我,我会修复它。
推荐阅读
- python - Plotly AttributeError:“Figure”对象没有“show”属性
- visual-studio - 在 Visual Studio 2019 中的哪里可以找到 gRPC 服务模板?
- ios - 实时应用程序崩溃与 EXC_BAD_ACCESS KERN_INVALID_ADDRESS
- iphone - 在 iPhone Safari 上支付视频
- html - 是否有任何CSS代码来自定义大小
HTML 元素? - google-cloud-firestore - 如何将字段添加到 Firestore 中的文档,然后添加集合?
- docker - 在 Jenkins 代理 docker 映像(使用 Kubernetes 插件)中运行业力测试时,ChromeHeadless 挂起
- python - 字符串“3d02h”中的确切日期
- python - 无法让文本换行或垂直居中与 xlsxwriter 一起使用
- php - 无法读入数组 JSON