gpt4 book ai didi

javascript - 为什么 block 级作用域中的函数不能改变形参?

转载 作者:数据小太阳 更新时间:2023-10-29 04:16:34 27 4
gpt4 key购买 nike

;(function(a){
if(true){
function a(){}
}
console.log(a) // 1
})(1)

;(function(){
var a = 0
if(true){
function a(){}
}
console.log(a) // function a(){}
})()

为什么块级作用域中的函数不能改变形参?

最佳答案

我不明白你为什么要这样做,但为了更好地理解 JavaScript 的一个极端情况,让我们探索一下。有时这有助于我们更好地理解语言的基础知识。

为了讨论起见,让我们考虑您的两个示例,分别作为案例 A 和案例 B:

// Case A - argument a is not overwritten
;(function(a){
if(true){
function a(){}
}
console.log(a) // 1
})(1)

// Case B - var a is overwritten
;(function(){
var a = 0
if(true){
function a(){}
}
console.log(a) // function a(){}
})()

为什么块级作用域中的函数声明不能​​改变形参

在 JavaScript 中 var没有块作用域,它有功能作用域,所以你不能假设每次看到 { }它为其中声明的变量创建了一个范围。基本上,功能块的工作方式与条件和迭代使用的其他块不同。

最近,与 ES2015 , 块作用域变量引入关键字 letconst .然而,作用域在 JS 中并不简单,因此您必须了解不同的关键字如何创建变量以及它们如何在不同的块结构中作用域,以及严格模式如何影响该行为。

事实证明,案例B是 var方式的侥幸和意外。和 function () {}声明在非严格模式下工作。

首先,在所有 JavaScript(包括严格模式)中,使用函数声明定义的函数,例如 function foo() {...}被提升到当前块级作用域的顶部!这意味着,在范围内,您永远无法覆盖 var通过函数声明。
// Case B modified
;(function(){
console.log(a) // function a(){}
var a = 0; // overwrites value of 'a'
function a(){}; // will be hoisted to top of block-level scope
console.log(a) // 0
})()

其次,在条件 if内块,函数声明被提升到它们定义的任何块的顶部,而不是周围的功能块。

第三,在 sloppy 模式(非严格)下,JavaScript,对于用 if 定义的函数声明块将允许该值覆盖用 var 声明的变量的值。在那个块之前。
// showing behavior of points #2 and #3:
;(function(){
console.log(a); // undefined
var a = 0;
console.log(a); // 0
if(true) {
console.log(a); // function a(){...} - a() was hoisted to top of if block
function a() {};
})();
console.log(a); // function a(){} - function declaration allowed to overwrite var declared above in surrounding function scope
})();

因此,您发现了一个奇怪的极端情况,即函数声明提升和作用域在非严格模式下表现不佳。它不会在严格模式下执行此操作,请参阅下面的下一节。

函数参数的行为更像用 let 定义的变量比 var s,所以这就是案例 A 的行为不像案例 B 的原因。并不是说块级作用域函数声明不能​​改变形式参数,而是它无论如何都不应该这样做,即使对于 vars 也是如此。案例 A 是它应该如何表现。

请注意,如果您使用 let而不是 var即使在草率模式下,事情也表现得更加一致:
// Case B using 'let' instead
;(function(){
let a = 0;
console.log(a); // 0
if(true) {
console.log(a); // function a(){}
function a() {};
}
console.log(a); 0
})();

另外, let只是一般表现得更好,例如,即使在草率模式下,尝试重新定义已经用 let 声明的变量不被允许:
// just try this!
let a = 0;
function a() {} // this will throw a syntax error

节点和浏览器的区别?不,它是关于严格模式的。

一些评论者指出浏览器中 Node.js 和 JavaScript 在这个问题上的区别。 claim 是这样的:
// in a browser
console.log(a) // Case A: 1
console.log(a) // Case B: function a(){}
// in node
console.log(a) // Case A: 1
console.log(a) // Case B: 0

但实际上,我只是在浏览器中使用 Codepen 和本地使用 Node(8.11.3 和 10.5.0)进行了测试,都返回了以下结果:
 // in Node and browser
console.log(a) // Case A: 1
console.log(a) // Case B: function a(){}

但是,当您设置 use strict 时指令,然后你会得到以下结果,但在 Node 和浏览器中都是一样的:
 // with 'use strict, in Node and browser
console.log(a) // Case A: 1
console.log(a) // Case B: 0

关于条件函数声明的建议

基本上,我不会这样做,除非我的函数总是返回一个函数。换句话说,在大多数情况下,我不会编写函数或方法来有时返回原始值而有时返回函数。

但让我们假设你想这样做。那么理所当然的,我总是会:
  • 使用 strict mode
  • 使用 letconst而不是 var See section 'Variables' here

  • 在这种情况下,我不会使用函数声明,而是将函数表达式分配给我的变量:
    ;(function(){
    let a = 0;
    console.log(a); // 0
    if(true) {
    console.log(a); // 0
    a = function () {}; // assign 'a' the value of the function
    }
    console.log(a); // function () { ... }
    })();

    为了我自己,我创建了一个 Codepen 来帮助解决所有这些问题: https://codepen.io/mrchadmoore/pen/jpEKaR?editors=0012

    关于javascript - 为什么 block 级作用域中的函数不能改变形参?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51279943/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com