为什么变量 f 的作用域会改变

早些时候在社区看到一个帖子,询问了一个关于 f = ? 的问题,今天又想起这个问题了,特意上来问一下,看看有没人可以解答疑惑的。


原题:

(() => {
  {
    function f () { 'A' }
    f = 1;
    f = 2;
    function f () { 'B' }
    f = 3;
  }
  console.log('f =', f);
})();

// logs f = 2

打了断点大概知道是因为作用域被修改了,但是不清楚为什么第二次函数声明会影响变量f的作用域。

后来有一个人提到说是:

比较反常识的是函数声明,可以看到函数声明的时候其实只把当前块内作用域的 f 复制一份放到函数块内,第一次和第二次函数声明都是这样的,如果当前块内作用域块内没有 f,那么就会在当前块内作用域声明一个 f 变量,再把函数赋值上去,紧接着再把块内的 f 复制一份到函数块内作用域。
阅读 1.8k
1 个回答

这种问题别研究了

(function () {
  {
    function f () { 'A' }
    f = 1;
    f = 2;
    function f () { 'B' }
    f = 3;
  }
  console.log('f =', f);
})();

改了一下尝试在ie下执行(ie11还是不支持箭头函数)
win 10 ie11的结果为f = function f () { 'B' }
win 10 ie11用ie10兼容模式跑结果为f = 3
使用browserstack测试chrome 30/firefox 30/safari 9.1跑结果为f = 3
chrome/firefox/safari最新版测试,结果为f = 2
具体原因就是非严格模式下block statement里函数声明的表现比较奇葩
这种问题真的不值得研究


https://stackoverflow.com/que...
image.png
如果我没理解错的话,应该是下面这种执行逻辑

"use strict";
(() => {
  var f₀ = undefined;
  {
    let f₁ = function () { 'A' };
    f₁ = function () { 'B' };
    f₀ = f₁;
    f₁ = 1;
    f₁ = 2;
    f₀ = f₁;
    f₁ = 3;
  }
  console.log('f =', f₀);
})();

在es6标准下应该是一个确定的结果(f = 2)
其他乱七八糟的结果应该是属于没有实现es6标准的浏览器(es5浏览器)的行为,根据文章所说,es5标准下在block statement中声明function是undefined behavior


在chrome控制台运行下面的代码也可以看到整段代码的执行中变量的变化过程,和上面分析的是一致的

(function () {
  debugger;
  {
    void 0;
    function f () { 'A' }
    f = 1;
    f = 2;
    function f () { 'B' }
    f = 3;
    void 0;
  }
  console.log('f =', f);
})();

image.png

image.png
↑这个时候右键点右边的Block -> f: f()选择show function definition可以知道这个函数是function f(){ 'B' }
image.png

image.png
↑此时Local -> f: f()function f(){ 'B' }
image.png

image.png

image.png

image.png

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