为什么JavaScript中没有提升回调函数?

时间:2016-04-16 05:58:52

标签: javascript hoisting

我理解JavaScript中的变量和函数声明的概念在封闭范围的顶部被提升。但是如果我有一个命名的回调函数,它就不会被挂起。我无法理解为什么会这样。我在下面的链接中有代码解释了方案

示例:

function enclosingScope () {
  var b;

  function inner (def) {
    def();  
  }
  var a = 2;
}

// After hoisting due to compilation, the above changes to 
function enclosingScope () {
  // Function declarations are hoisted before variables
  function inner (def) {
    def(); 
  }

  var b, a;
  a = 2
}

// But if I have a named callback, will that be hoisted?
function enclosingScope () {
  function inner (def) {
    def();
  }

  var b, a;
  a = 2

  inner(function cb () {
    console.log('Test callback hoisting')
  })
}

2 个答案:

答案 0 :(得分:3)

有问题的行为不仅限于命名回调。这是任何命名函数表达式的工作方式。请考虑以下事项:

function foo() {
  (function baz() { });
  console.log(typeof baz);
}

> foo()
< undefined

baz无法访问其正文。所以这与提升不同。

答案 1 :(得分:1)

我发现答案太短了,所以这里有一个更典型的解释:

Javascript区分函数声明

function f() {}

和函数表达式

var f = function () {} // anynomous function or lambda
var g = function h() {} // named function expression

函数声明是语句,而函数表达式是......,猜猜是什么?表达方式。请注意,命名函数表达式的名称(给定示例中为h)只能在函数体(在给定示例中为g)内访问。

每当在括号中嵌套函数声明时,它都会自动转换为表达式。这意味着您的function cb () {...}只是一个命名函数表达式。但是你不能将它分配给变量,而是将其作为参数传递给inner

当涉及与函数表达式相关的提升时,仅提升已分配变量的声明。这不是函数声明的情况:

console.log(f); // function f
console.log(g); // exists, but undefined
console.log(h); // reference error

function f() {}
var g = function h() {}

由于示例中的cb未分配给变量,因此无法提升。

因此,这两条线相当于吊装:

inner(function cb(){});
(function cb(){});

加分: const / let

但是,当您尝试调用使用constlet声明的函数表达式时,在声明之前,会在词法上引发错误:

console.log(g); // reference error
const g = function h() {}

g也被提升了。但要保护您免受意外undefined的攻击。解释器抛出一个错误。我认为这是明智的。