在javascript中,为什么默认参数在函数内部是不可变的?
为什么在javascript中,默认参数不能在函数内部更改,而非默认参数可以更改在javascript中,为什么默认参数在函数内部是不可变的?,javascript,arguments,immutability,default-arguments,Javascript,Arguments,Immutability,Default Arguments,为什么在javascript中,默认参数不能在函数内部更改,而非默认参数可以更改 function func(a) { a = 99; // updating a also updates arguments[0] console.log(arguments[0]); } func(10); // prints 99 vs 看看: 仅传递简单参数(即,不是rest、默认或重构参数)的非严格函数将使函数体中的变量值和新值与arguments对象同步,反之亦然: 而且 function f
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // prints 99
vs
看看:
仅传递简单参数(即,不是rest、默认或重构参数)的非严格函数将使函数体中的变量值和新值与arguments对象同步,反之亦然:
而且
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // 99
// An untracked default parameter
function func(a = 55) {
console.log(arguments[0]);
}
func(); // undefined
相反,传递rest、default或destructured参数的非严格函数不会将函数体中分配给参数变量的新值与arguments对象同步。相反,具有复杂参数的非严格函数中的arguments对象将始终反映调用函数时传递给函数的值(这与所有严格模式函数所表现的行为相同,无论传递的变量类型如何):
及
而且
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // 99
// 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)
[为函数f(0x38db0826b679)生成的字节码]
参数计数2
寄存器计数4
帧大小32
0x38db0826b846@0:88 CreateUnmappedArguments
0x38db0826b847@1:26 fb Star r0:将累加器存储在寄存器0中(默认为函数帧指针)
0x38db0826b849@3:0c 63 LdaSmi[99]:在累加器中加载(SMallInteger)99
0x38db0826b84b@5:26 02星a0:将累加器存储在函数参数0中
0x38db0826b84d@7:13 00 LdaGlobal[0],[0]:我不知道
0x38db0826b850@10:26 f9星形r2:将累加器存储在寄存器2中
0x38db0826b852@12:28 f9 01 02 LdaNamedProperty r2[1],[2]:在蓄能器中加载a
0x38db0826b856@16:26 fa星形r1:将累加器存储在寄存器1中
0x38db0826b858@18:0b LdaZero:蓄能器中的负载为0
0x38db0826b859@19:2a fb 04 LdaKeyedProperty r0,[4]:(假定)正在使用键4加载属性
从带有蓄能器的功能框架
(同步)此处的参数。
0x38db0826b85c@22:26 f8星形r3:将累加器存储在寄存器3中
0x38db0826b85e@24:59 fa f9 f8 06 CallProperty1 r1、r2、r3[6]:console.log(r1)
0x38db0826b863@29:0d LdaUndefined:累加器中未定义负载
0x38db0826b864@30:aa返回:返回累加器值
固定池(大小=2)
处理程序表(大小=0)
震源位置表(大小=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)
[为函数f(0x3bd80826b679)生成的字节码]
参数计数2
寄存器计数4
帧大小32
0x3bd80826b846@0:88 CreateUnmappedArguments
0x3bd80826b847@1:26 fa星形r1:将累加器存储在寄存器1中(假定为函数帧指针)
0x3bd80826b849@3:25 02 Ldar a0:在累加器中加载参数0
0x3bd80826b84b@5:9e 06跳线未定义[6](0x3bd80826b851@11):如果累加器未定义:
0x3bd80826b84d@7:0c 37 LdaSmi[55]:累加器中的负载(小整数)55
0x3bd80826b84f@9:8b 04跳转[4](0x3bd80826b853@13):否则:
0x3bd80826b851@11:25 02 Ldar a0:累加器中的加载参数0
0x3bd80826b853@13:26 fb Star r0:将累加器存储在寄存器0中
0x3bd80826b855@15:0b LdaZero:蓄能器中的负载为0
0x3bd80826b856@16:26 f8星形r3:将累加器存储在寄存器3中
0x3bd80826b858@18:0c 63 LdaSmi[99]:在累加器中加载(SMallInteger)99
0x3bd80826b85a@20:30 fa f8 00 StaKeyedProperty r1,r3,[0]:(假定)在函数帧中加载
(r1)蓄能器(99)在
具有键r3(0)的属性(同步)
0x3bd80826b85e@24:13 00 02 LdaGlobal[0],[2]:(假定)正在加载包含
指向累加器中的
0x3bd80826b861@27:26 f8星形r3:将累加器存储在寄存器3中
0x3bd80826b863@29:28 f8 01 04 LdaNamedProperty r3[1],[4]:在蓄能器中加载a
0x3bd80826b867@33:26 f9星形r2:将累加器存储在寄存器2中
0x3bd80826b869@35:59 f9 f8 fb 06 CallProperty1 r2,r3,r0[6]:console.log(r2)
0x3bd80826b86e@40:0d LdaUndefined:累加器中未定义负载
0x3bd80826b86f@41:aa返回:返回累加器值
固定池(大小=2)
处理程序表(大小=0)
震源位置表(大小=0)
如您所见,第二段代码与第一段代码类似,添加了一条if语句来检查可选参数
最后,deno中的v8googleengine
将10
打印两次。
这很奇怪,但我想这是有原因的。
可能是有人在实施过程中做出了这一决定,而不是每个人都反映了变化
[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)