【问题标题】:Why arrow function has to be declared above the caller function为什么箭头函数必须在调用函数之上声明
【发布时间】:2020-08-23 05:46:22
【问题描述】:

在 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没有定义,如果我使用@987654327它也不起作用@关键字来定位foo函数,我假设this是指全局/文档级别

// 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类中声明箭头函数时,它只能与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();

【问题讨论】:

  • 与箭头无关,与const的范围有关
  • 另外,即使 const foo 高于 myCaller,this.foo 随后也会失败 - 因为 const 和 let 变量未添加到“全局”对象 - this 可能是全局对象(窗口在浏览器上)在您的代码中
  • @JaromandaX 我应该删除const 吗?我无法删除const...如果我删除const,则会出现编译错误foo is not defined
  • @BaruchMashasha 感谢您的链接,但我认为这在这里没有帮助,因为我没有执行myCaller 函数,因为它已经生成了编译错误,此外,为什么它在它起作用时使用 function 关键字但不用于箭头函数?

标签: javascript this arrow-functions function-declaration


【解决方案1】:

您声明的任何变量(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 都作为属性附加到窗口对象。现在您可以直接引用它们,例如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 时,它指的是窗口对象,foo 不是窗口对象的属性。这就是为什么,即使你将const foo 放在myCaller 定义之上,它也不起作用。

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

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

【讨论】:

  • 您应该解释为什么myCaller 中的this 是(或可能不是)全局对象...
  • 类中的 foo() 不一定是从 global 上下文中查找的,只需从周围的任何范围内查找即可。
  • JavaScript 也被编译,只是在需要的基础上。它仍然会抛出编译错误;在编译/解析阶段抛出语法错误。这与运行时错误不同。
  • 谢谢@chethan7!它解释得很好!我想更好地理解一件事,在上课的情况下,如果我在课堂外声明foo(),那么我可以直接在我的课堂方法中调用foo(),这是否意味着现在是因为附加了foo()global windows 上下文,这就是为什么我可以在我的类方法中调用它?
  • 你提到了That is why, even if you put const foo above myCaller definition, it won't work. 实际上,如果我直接调用foo() 而不使用this,它确实有效...当我调用this.foo() 时它不起作用,但既然你提到了,当遇到constlet 时,JS 为它们分配内存但不使它们成为 Window 对象的一部分,这可能解释了为什么this.foo() 不起作用,因为目前this 指的是 windows 上下文,但是,为什么这次没有this 的电话会起作用吗?
猜你喜欢
  • 2012-07-16
  • 2019-12-01
  • 2018-07-03
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多