下面这段 JavaScript 代码,我的参数去哪里呢?

image.png

上面这段代码可能变量提升的原因,但是下面我的参数为什么又没被覆盖呢?

image.png

回复
阅读 797
4 个回答

不要把时间浪费在这种毫无意义的问题上,你应该把时间花在这门语言能干些什么上
就以你的这个问题为例用node --print-bytecode --print-bytecode-filter=a a.js生成的字节码是这样的

[generated bytecode for function: a (0x0004e50dbb29 <SharedFunctionInfo a>)]
Bytecode length: 40
Parameter count 2
Register count 2
Frame size 16
OSR nesting level: 0
Bytecode Age: 0
   10 E> 00000004E50DC796 @    0 : 7f 00 00 02       CreateClosure [0], [0], #2 // 创建b函数的一个闭包
         00000004E50DC79A @    4 : 18 03             Star a0  // 将闭包赋值给第一个参数寄存器
   19 S> 00000004E50DC79C @    6 : 21 01 00          LdaGlobal [1], [0]  // 获取全局console
         00000004E50DC79F @    9 : c2                Star1    // 将console存储到r1寄存器中
   27 E> 00000004E50DC7A0 @   10 : 2d f9 02 02       LdaNamedProperty r1, [2], [2]  // 冲常量池中取出字符串'log'
         00000004E50DC7A4 @   14 : c3                Star0 // 将字符串'log'存入寄存器r0中
   27 E> 00000004E50DC7A5 @   15 : 5d fa f9 03 04    CallProperty1 r0, r1, a0, [4] // 调用console他的成员'log' 参数为a0(先前被赋值为b的一个闭包)
   46 S> 00000004E50DC7AA @   20 : 0d 0a             LdaSmi [10] // 将10载入acc寄存器
         00000004E50DC7AC @   22 : 18 03             Star a0  // 从acc寄存器去除10到a0寄存器
   72 S> 00000004E50DC7AE @   24 : 21 01 00          LdaGlobal [1], [0] // 又是加载console的逻辑同上
         00000004E50DC7B1 @   27 : c2                Star1
   80 E> 00000004E50DC7B2 @   28 : 2d f9 02 02       LdaNamedProperty r1, [2], [2]
         00000004E50DC7B6 @   32 : c3                Star0
   80 E> 00000004E50DC7B7 @   33 : 5d fa f9 03 06    CallProperty1 r0, r1, a0, [6] // 再次调用注意这里a0的值已经存储了小整数10
         00000004E50DC7BC @   38 : 0e                LdaUndefined // 加载undefined到acc寄存器上
   89 S> 00000004E50DC7BD @   39 : a8                Return  // 函数返回
Constant pool (size = 3)
00000004E50DC739: [FixedArray] in OldSpace
 - map: 0x03c05fd812c1 <Map>
 - length: 3
           0: 0x0004e50dc6e9 <SharedFunctionInfo b>
           1: 0x00f3dff21bb1 <String[7]: #console>
           2: 0x0146912a9f31 <String[3]: #log>
Handler Table (size = 0)
Source Position Table (size = 20)
0x0004e50dc7c1 <ByteArray[20]>

可以看到不管是函数b,还是重新的变量声明b都被当作了对a0寄存器的重新赋值(a0在这里表示为第一个参数寄存器),所以他的等价代码应该为

function a(b) {
  b = function b(){}; 
  console.log(b);
  b = 10;
  console.log(b);
}

a(1);

没人会写这种代码,相比这种毫无价值的问题,你更应该去了解,字节码是什么,什么是栈式虚拟机,什么是寄存器虚拟机,编译器是什么,闭包是怎么实现的
v8字节码解释
还有什么不懂可以问chatgpt

首先要知道函数和变量都会提升,
只有声明本身会被提升,而赋值操作不会被提升。
函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被同名变量赋值后覆盖。
函数声明会被提升,但函数表达式不会被提升。

https://blog.csdn.net/qq_4369...

其实代码是这样执行的
// b = 1是在函数提升和变量提升前执行的
function a (b) {
  function b () {}
  var b
  console.log(b);
  b = 10
  console.log(b);
}
a(1)
// a=99是在函数提升和变量提升后执行的
function f1 () {
    function a() {}
    var a
    a=99
    console.log(a)
    console.log(a)
    a = 1
    console.log(a)
}
f1()

首先形参b可以理解为:

  function a (var b) {
    console.log(b);
    var b = 10
    function b () {
    }
    console.log(b);
  }

也就是定义了b代码就变成了:

  function a () {
    // 因为传入的是1
    var b = 1
    console.log(b);
    var b = 10
    function b () {
    }
    console.log(b);
  }

就是重新定义了b并赋值为1, 这样结果就可以理解了:
函数a内函数与变量提升, 此时b是函数, 打印就是函数, 而后var b = 10, b就变成了10就打印了10

那是因为覆盖掉了, 不太建议这这上面纠结太多时间, 在开发时根本不能这样写会被骂

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏