y = 4
function a(y) {
console.log(y)
}
function b() {
let x = 3;
a(x)
}
b() //结果为什么是3?不是4,函数a的作用域不是全局嘛?
回答
function函数的作用域取决于你执行的作用域 而不是声明时候的作用域
只有es6的箭头函数才是取决于你声明的作用域 而不是执行的作用域
这个其实就是看你理不理解作用域了,在你执行的时候,执行到a(x),会在b的作用域内找有没有变量x,如果没有,就沿着作用域链查找。因为,b的作用域内有一个x,所以实参的值就是3
老实说,总拿这种违反人类的写法去了解作用域只会加重作用域的迷惑,上述的代码真要放在一个合格的团队里至少它不会是成功,光代码格式化都已经会认为这是错误的了。
如果你在 TypeScript 下,它可能会是这样子:
const y = 4; // 不得不写上声明定义
function a(y: number) { // 不得不写上 `y` 类型
console.log(y)
}
// other
可能你还有点懵,但如果你配合 TsLint 你会发现上面的代码压根就不让你通过,因为会让你得到一个 no-shadowed-variable 的警告,而你不得不改成这样子:
const y = 4;
function a(val: number) {
console.log(val)
}
// other
最后你会发现这里压根没有所谓作用域的迷惑了,因为那些在你看来有迷惑的只不过没有良好的编码风格引起的,这里不存在 y 与 y 之类的迷惑,val 就是一个简单不过的函数作用域,而 y 也只不过是全局作用域罢了,他们名称不同你在光看就很容易理解。
至于那些所谓的函数提升作用域,如果你严格按先声明后使用的规则,压根就没有这种事情存在。
再退一步讲,如果可能你还需要函数柯里化,可能会遇到嵌套作用域(或闭包),除非在做基础架构否则很难遇到,即便遇到届时你早就会用 class,那会你再想遇到闭包都难。
编程应该如何利用工具链,它会帮我们杜绝很多因为自身的不标准,倒置一些让人迷惑的事发生,但本身并不是语言的错,而更多的是历史问题
以上。