表达式和语句的区别
表达式和语句的区别在于, 有没有返回值.
表达式
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执行前的解析
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)。