(() => {
{
function f() { 'A' }
f = 1;
f = 2;
function f() { 'B' }
f = 3;
}
console.log('f =', f);
})();
1
Jooooooooo 2021-05-31 14:59:04 +08:00
[] - []; // ?
{} - {}; // ? [] - {}; // ? {} - []; // ? 找出会返回 -0 的那一项. |
2
AoEiuV020 2021-05-31 15:02:29 +08:00
f=2,因为我在 console 跑过了,
|
3
Jirajine 2021-05-31 15:06:21 +08:00
我感觉应该是 undefined 才对,是因为没开 strict mode 么。
|
4
thunderw 2021-05-31 15:46:15 +08:00 2
|
5
dfkjgklfdjg 2021-06-01 10:56:38 +08:00
我们在先在每次为 f 赋值之后输出以下 f 的值
```js (() => { { function f() { 'A' } console.log('f_1 =', f); // f_1 = ƒ f() { 'B' } f = 1; console.log('f_2 =', f); // f_2 = 1 f = 2; console.log('f_3 =', f); // f_3 = 2 function f() { 'B' } console.log('f_4 =', f); // f_4 = 2 f = 3; console.log('f_5 =', f); // f_5 = 3 } console.log('f_out =', f); // f_out = 2 })(); ``` 好了,那么有疑惑的点只会在 f_1 = ƒ f() { 'B' } 、f_4 = 2 和 f_out = 2 上对不对,其它的都是符合直觉的。 首先来看为什么 f_1 = ƒ f() { 'B' } 与 f_4 = 2 其实正确的书写方式应该是 1.声明函数; 2.声明变量; 3.业务逻辑; 所以简单改正之后其实类似这样 ```js (() => { var f { f = function () { 'A' } f = function () { 'B' } console.log('f_1 =', f); // f_1 = ƒ f() { 'B' } f = 1; console.log('f_2 =', f); // f_2 = 1 f = 2; console.log('f_3 =', f); // f_3 = 2 console.log('f_4 =', f); // f_4 = 2 f = 3; console.log('f_5 =', f); // f_5 = 3 } console.log('f_out =', f); // f_out = 2 })(); ``` 那么就剩下一个疑惑了,就是为什么 最后的 f_out = 2 明明之前已经输出了 f_5 = 3,这个我就不知道原理了,只能从 block scope 和 local scope 和你说 我把外部 local scope 中的 f 继续声明成 f , 而内部 block scope 中的 f 的声明成 _f: ```js (() => { var f { var _f f = _f = function () { 'A' } f = _f = function () { 'B' } console.log('f_1 =', _f); // f_1 = ƒ f() { 'B' } _f = 1; console.log('f_2 =', _f); // f_2 = 1 _f = 2; console.log('f_3 =', _f); // f_3 = 2 f = _f console.log('f_4 =', _f); // f_4 = 2 _f = 3; console.log('f_5 =', _f); // f_5 = 3 } console.log('f_out =', f); // f_out = 2 })(); ``` 具体为什么可能需要大佬来解释了。 |
6
libook 2021-06-01 14:44:16 +08:00
可以逐行调试,然后看每一行执行完后,f 在不同作用域下的值是什么:
// 此时没有 f (() => { f = -1; // 函数块内:-1 { f = 1; // 块内:1 函数块内:-1 function f() { 'A' } // 块内:f() 函数块内:f() f = 1; // 块内:1 函数块内:f() f = 2; // 块内:2 函数块内:f() function f() { 'B' } // 块内:2 函数块内:2 f = 3; // 块内:3 函数块内:2 } console.log('f =', f); // 输出函数块内的 f 值,即 2 })(); 可以看出来,把操作分成两类,一类是赋值,另一类是函数声明。 赋值的逻辑很简单,就是直接影响当前块内作用域的 f 值,执行到哪就赋值成啥。 比较反常识的是函数声明,可以看到函数声明的时候其实只把当前块内作用域的 f 复制一份放到函数块内,第一次和第二次函数声明都是这样的,如果当前块内作用域块内没有 f,那么就会在当前块内作用域声明一个 f 变量,再把函数赋值上去,紧接着再把块内的 f 复制一份到函数块内作用域。 以上是我根据行为做出的推断,实际上还是得看 ES 标准以及引擎的实现方案。 不过这个说白了还是老生常谈的 ES5 作用域提升的特性,在严格模式+块级作用域下是不会有这种现象的,而且如今的商业开发也极少会考虑保留作用域提升特性,拥抱 ES6+或使用 TS 都在团队开发效率方面有很高的回报。 |
7
libook 2021-06-01 14:46:22 +08:00
上面代码编辑有问题,更新一个正确的版本:
// 此时没有 f (() => { f = -1; // 函数块内:-1 { f = 1; // 块内:1 函数块内:-1 function f() { 'A' } // 块内:1 函数块内:1 f = 1; // 块内:1 函数块内:f() f = 2; // 块内:2 函数块内:f() function f() { 'B' } // 块内:2 函数块内:2 f = 3; // 块内:3 函数块内:2 } console.log('f =', f); // 输出函数块内的 f 值,即 2 })(); 第一次函数声明的时候就是做了值的复制,所以内外都是 1 |
8
mxT52CRuqR6o5 2021-07-07 17:35:58 +08:00
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 严格模式下直接报错 |