简单理解--函数声明与函数表达式

242 阅读2分钟

表达式和语句的区别

表达式和语句的区别在于, 有没有返回值.

表达式

a = 1 //  这是一个表达式, 返回了1
6 === 5 // 这是一个表达式, 返回了 false

语句

var a // 这是一个语句, 没有返回值
function foo () {} // 这是一个语句, 没有返回值
if(1) { console.log(1) } // 这也是一个语句, 没有返回值

函数声明和函数表达式

函数声明

函数声明就是一个语句. 没有返回值.

foo()
function foo(){
    console.log('foo')
}

// foo

函数表达式

函数表达式就是返回了一个函数对象.

foo()
var foo = function (){
    console.log('foo')
}
// Uncaught TypeError: foo is not a function

也是因为声明方式的差异, 导致输出的不一样.

js执行前的解析

image.png

js在执行之前, 有一个解析的流程, 会生成ast和作用域, 作用域就是用来找变量的.

那v8在解析 函数声明函数表达式, 中间处理是不一样的.

中间区别在于:

  • 表达式返回的是值, 解析阶段用个标识符表示这有个值就行. 再到执行阶段会有赋值的操作.
  • 而语句,表示一段执行过程, 在执行阶段是没有赋值操作的. 所以需要再解析阶段提前就声明好.

解析函数声明

function foo() {}

这里在解析阶段, 就将整块代码存到堆内存上, 执行的时候直接执行.

foo()
function foo(){
    console.log('foo')
}

// foo

所以在执行这段代码的时候, foo 已经提前声明好了, 也就是函数声明提升了.

解析函数表达式

当我们在执行

var a = 1

实际上是在执行两步, 因为这是表达式.

// 解析过程
var a = undefined
// 执行过程
a = 1

当我们再执行

var foo = function () {}

实际上

// 解析过程
var foo = undefined
// 执行过程
foo = function() {}

看这个例子:

foo()
var foo = function (){
    console.log('foo')
}
// Uncaught TypeError: foo is not a function

所以我们再解析这段代码的时候, var foo 还是个undefined, 需要执行到赋值的时候才知道是个什么.

总结

在 V8 解析 JavaScript 源码的过程中,如果遇到普通的变量声明,那么便会将其提升到作用域中,并给该变量赋值为 undefined,如果遇到的是函数声明,那么 V8 会在内存中为声明生成函数对象,并将该对象提升到作用域中。

函数表达式与函数声明的最主要区别:

  • 函数表达式是在表达式语句中使用 function 的,最典型的表达式是“a=b”这种形式,因为函数也是一个对象,我们把“a = function (){}”这种方式称为函数表达式;
  • 在函数表达式中,可以省略函数名称,从而创建匿名函数(anonymous functions);
  • 一个函数表达式可以被用作一个即时调用的函数表达式——IIFE(Immediately Invoked Function Expression)。