一道 js 脑筋急转弯求解

2021-12-30 16:15:55 +08:00
 cheese
    {
      function a(){}
      a=1
      function a(){}
    }
    console.log(a,"1");
    {
      function a(){}
      a=1
      
    }
    console.log(a,"2");
    //输出
    //1 '1'
    //ƒ a(){} '2'

为啥第二个块的 a = 1 没有覆盖到全局的 a

3015 次点击
所在节点    JavaScript
33 条回复
murmur
2021-12-30 16:20:31 +08:00
function a(){} 1
function a(){} 2

这是 IE 的结果

所以出题人傻逼,完毕。
murmur
2021-12-30 16:21:36 +08:00
对了,刚才的结果也适用于 edge 浏览器,edge 够现代吧,不适用于 chrome
所以这不是出题人傻逼是什么
abear
2021-12-30 16:21:46 +08:00
先定义的不管,后定义的招殃
mxT52CRuqR6o5
2021-12-30 16:22:25 +08:00
vanton
2021-12-30 16:23:50 +08:00
这个题目不成立啦,不同环境不一样的。
mxT52CRuqR6o5
2021-12-30 16:28:42 +08:00
"use strict";
let a₀ = undefined;
{
let a₁ = function ( ){ };
a₁ = function ( ){ };
a₀ = a₁;
a₁ = 1;
a₀ = a₁;
}
console.log(a₀, "1");
{
let a₁ = function ( ){ };
a₀ = a₁;
a₁ = 1;
}
console.log(a₀, "2");
大概就是这么个逻辑
也是因为非严格模式下块作用域有非常奇怪的难以理解的表现,所以搞了个严格模式出来
mxT52CRuqR6o5
2021-12-30 16:30:49 +08:00
es6 标准浏览器的非严格模式下运行这段代码是有一个固定确定的结果的,就是上面说的那个非常奇怪的难以理解的运行逻辑
iikebug
2021-12-30 16:33:24 +08:00
@mxT52CRuqR6o5 严格模式下,上面那段代码都跑不起来吧
libook
2021-12-30 16:33:50 +08:00
这个不是脑筋急转弯,这个是作用域提升,声明变量省略的 var 和 funciton 关键字都有作用域提升的特性。

第一个块的执行顺序实际上是先把两个 funciton 提到全局作用域,因为下面 console.log 输出 a ,所以稍后 a 也提到全局作用域,那么 a 的值变化就是先赋值为第一个 function ,再赋值为第二个 function ,最后赋值为 1 ,块下面 console.log 就输出 a 值为 1 。

第二个块里面,同样把 function 提到全局,后续因为此时全局已经有 a 了,后面的 console.log 能找到 a ,所以块内的 a 被认为是局部变量没有被提升作用域,所以块下面的 console.log 输出的是第二个块提升出去的 funciton a 。

换个写法可以帮助你理解这个顺序:

{
console.log(a(),"1");
function a(){return 2}

a=1
function a(){return 3}
}
console.log(a,"4");
{
function a(){return 5}
a=2
console.log(a,"6");
}
console.log(a(),"7");
mxT52CRuqR6o5
2021-12-30 16:34:56 +08:00
@iikebug 是的,会有 runtime error
EPr2hh6LADQWqRVH
2021-12-30 16:37:13 +08:00
我不知道,我只知道谁敢拿这个给我看我当场让他滚蛋
66beta
2021-12-30 16:39:33 +08:00
{
console.log(1, window.a, a);
function a() {}
console.log(2, window.a, a);
a = 1;
console.log(3, window.a, a);
function a() {}
console.log(4, window.a, a);
}
console.log('========', a, "1");
{
console.log(5, window.a, a);
function a() {}
console.log(6, window.a, a);
a = 1;
console.log(7, window.a, a);
}
console.log('========', a, "2");

1 、函数声明提升到块级顶部
2 、块内访问 a 是块内的,外面访问的是全局的
Biwood
2021-12-30 16:40:24 +08:00
脑筋急转弯可还行
cheese
2021-12-30 16:44:08 +08:00
@murmur #2 edge 及 chrome 我都复现了,chrome 内核下的非严格模式表现应该是一致的。
iikebug
2021-12-30 16:44:30 +08:00
不能跑严格模式的都叫他滚。真就面试八股文?
murmur
2021-12-30 16:45:39 +08:00
@cheese edge 非 chrome 内核是我的结果,直接命令行打出来啊,要是别人出题有严格模式你跟我们说没严格模式,那是你的问题
cheese
2021-12-30 16:46:43 +08:00
@mxT52CRuqR6o5 #6 我自己的推测也是类似这个逻辑,但是我没法理解为什么。第二个块到 a₁ = 1;就停止了,而没有 a₀ = a₁; 这个步骤
churchill
2021-12-30 16:54:03 +08:00
https://tc39.es/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics

> Prior to ECMAScript 2015, the ECMAScript specification did not define the occurrence of a FunctionDeclaration as an element of a Block statement's StatementList. However, support for that form of FunctionDeclaration was an allowable extension and most browser-hosted ECMAScript implementations permitted them. Unfortunately, the semantics of such declarations differ among those implementations.
churchill
2021-12-30 16:54:59 +08:00
js 版的 ub 而已,:)
mxT52CRuqR6o5
2021-12-30 16:58:40 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/825334

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX