为什么箭头函数必须声明在调用函数之上

Why arrow function has to be declared above the caller function

在 javascript 文件中,当我使用 function 关键字声明函数时,我可以将函数放在调用函数之后,例如

// test.js
function myCaller() {
   foo('hello world');    // this works!
   this.foo('hello world');  // this works!
}
function foo(text) {
   console.log('foo called!', text);
}
myCaller()

但是如果我把foo变成一个箭头函数,放在同一个位置,那么在myCaller函数中,它说foo没有定义,也赢了如果我使用 this 关键字定位 foo 函数,我假设 this 指的是 global/document 级别

// test.js
function myCaller() {
   foo('hello world');    // es-lint warning: 'foo' was used before it was defined
   this.foo('hello world');  // compilation error: foo is not defined
}
const foo = (text) => {
   console.log('foo called!', text);
}
myCaller();

- 我错了,我认为不使用 this 的第二种方法不起作用,因为 not defined 的 javascript 编译错误,但这实际上是我的 eslint 错误 - 'foo' was used before it was defined,是不是不建议这样做?

为什么会这样,这是否意味着我们必须始终在 caller 函数上方声明箭头函数?有没有其他方法可以解决这个问题?

const foo = (text) => {
   console.log('foo called!', text);
}
// test.js
function myCaller() {
   foo('hello world');    // this works! no es-lint warning now
   this.foo('hello world');  // no compilation error but there is a run-time error : 'this.foo is not a function'
}

myCaller();

此外,我发现当在 javascript class 中声明箭头函数时,它只能与 this 关键字一起使用,如果调用者函数也是箭头函数函数带有 function 关键字,这将不起作用...

// myTest.js
class myTest {
   myCaller() {
      foo('hello world');    // compilation error: foo is undefined
   }
   myCaller2 = () => {
     this.foo('hello world'); //this works!
   }
   foo = (text) => {
      console.log('foo called!', text);
   }
}
new myTest().myCaller();
new myTest().myCaller2();

您声明的任何变量(letconst 变量除外)或您在全局上下文中定义的函数(例如,直接在 test.js 中)将附加到 Window 对象。所以,当你写的时候,

// test.js
function myCaller() {
   foo('hello world');    // this works!
   this.foo('hello world');  // this works!
}
function foo(text) {
   console.log('foo called!', text);
}
myCaller()

myCallerfoo 都作为属性附加到 window 对象。现在您可以直接引用它们,例如 foo()(此处隐含)或 this.foo() 甚至 window.foo()。由于js使用了提升,这些变量或函数先附加到上下文,然后开始执行。

但是 constlet 没有附加到 Window 对象(否则它们可以随处访问,表现得与 var 完全一样)。所以当你写

// test.js
function myCaller() {
   foo('hello world');
   this.foo('hello world');
}
const foo = (text) => {
   console.log('foo called!', text);
}
myCaller();

Javascript 引擎扫描整个脚本以查看是否定义了任何变量或函数。在这个提升阶段,如果它找到 constlet,它会为它们分配内存但不会使它们成为 Window 对象的一部分。因此,当您在全局上下文中引用 this 时,它指的是 window 对象,而 foo 不是 window 对象的 属性。这就是为什么,即使你把 const foo 放在 myCaller 定义之上,它也不起作用。

在 class 的情况下,如果您尝试直接调用 foo() 而不引用它,它会尝试从封闭的上下文中访问它,而您的示例中没有定义它。所以它会抛出错误。如果您在 class 之外用 var 定义另一个 foo() 或直接定义为 foo = (text) => ...,它将起作用。

( this 可能并不总是指全局上下文。函数和 classes 可以有自己的自定义上下文,而 this 会引用该上下文。但是当函数或 classes 没有定义自定义上下文,全局上下文将是 this 关键字将引用的上下文。this 未定义函数和 class在严格模式下是默认的。有几个这样的警告需要考虑。)