资讯专栏INFORMATION COLUMN

详解函数与变量的声明与提升

马忠志 / 1367人阅读

摘要:注意是前面,而不是最前面,因为变量声明提升的优先级别要低于函数声明提升。分解后是这样从以下代码可以看出这也印证了变量声明提升与变量定义分两步走的结论。

函数声明

定义函数有两种方式: 一种是函数声明,另一种是函数表达式。
函数声明语法如下:

function functionName(arg0, arg1, arg2) {
    // 函数体
}
函数声明提升

所谓的函数声明提升,是指在一个作用域中,如果声明了一个函数,那么在代码执行的时候,会将这个声明提升到整个作用域的最前面来执行。看下面的例子。

printString("hello world")

function printString(string) {
    console.log(string)
}

将代码整体复制到控制台,会打印出hello world
再看函数内部作用域:

function outer() {
    inner("hello world")
    
    function inner(string) {
        console.log(string)
    }
}
outer()  // hello world

这样也得到了正确的输出。

为什么在函数声明之前就可以调用呢?就是因为函数声明提升。
所以,无论函数声明被写在所处作用域的哪里,都会被提升到这段代码的最前面。

重复声明函数

如果在已经声明了一个函数的情况下,声明另一个同名函数,将会覆盖前面一个。

function b() {console.log(1)}
function b() {console.log(2)}
b()  // 2

上述代码中,真正执行的是后面声明的函数。

函数声明的实质

函数声明实质上是定义了一个变量,该变量是Function的实例, 它指向了一个函数。

function newF() {
    console.log("hello")
}

console.log(typeof newF) //  "function"
console.log(newF instanceof Function) // true

这样的话,就不难理解为什么声明重名函数,会覆盖前面一个了,这相当于重新给这个变量赋了一个值。

变量定义

定义一个变量的语法如下:

var a
var b

实际上是用var声明了一个新的变量,变量被声明时默认值为undefined

变量声明并初始化的实质

这里说的变量声明并初始化是指下面这种方式:

var a = 1;

实际上这行代码是分两步执行的:

先声明变量

var a = undefined;

给变量赋值

a = 1;

这也是为什么可以用一个变量给另一个变量做初始化的原因。看下面的代码:

var b = 3;
var a = b
console.log(a) // 3

实际上分了四步:

声明b: var b = undefined;

生命a: var a = undefined;

给b赋值: b = 3;

给a赋值: a = b;

变量声明提升

变量的声明也可以提升,也就是说JS在执行时,会把变量声明的代码提升到这个作用域代码段的前面。注意:是前面,而不是最前面,因为变量声明提升的优先级别要低于函数声明提升。
看下面代码:

console.log(foo)
var foo = 3

执行结果是undefined。实际执行顺序为:

var foo = undefined
console.log(foo)
foo = 3
重复声明变量

如果声明一个已经声明过的变量,JS会忽略第二次声明。但是如果在声明时给变量赋值,那么会覆盖之前的值。

var foo1 = 3;
var foo1
console.log(foo1) // 3

拆开来看,是如下代码:

var foo1 = undefined;
foo1 = 3;
var foo1 = undefined; // 这行代码被忽略。不会执行
console.log(foo1) // 3
声明一个与函数声明的名字相同的变量

如果声明了一个变量,这个变量和某个函数声明具有同样的名字,那么也会忽略这个变量声明。

function foo3() {}
var foo3
console.log(foo3)  // function foo3() {}

但是如果声明变量时进行了初始化就不一样了,相当于给变量重新赋值:

function foo3() {}
var foo3 = 3
console.log(foo3)  // 3
函数表达式

另一种定义函数的方式是函数表达式,语法如下:

var func = function(){
    console.log("hello")
}

实际上,这就是一个变量声明并初始化的代码。分解后是这样:

var func = undefined;
func = function(){
    console.log("hello")
}

从以下代码可以看出:

console.log(func) // undefined
var func = function(){}
console.log(func)  // function (){}

这也印证了变量声明提升变量定义分两步走的结论。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84045.html

相关文章

  • ES6 变量作用域提升变量生命周期详解

    摘要:不同的是函数体并不会再被提升至函数作用域头部,而仅会被提升到块级作用域头部避免全局变量在计算机编程中,全局变量指的是在所有作用域中都能访问的变量。 ES6 变量作用域与提升:变量的生命周期详解从属于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章。本文详细讨论了 JavaScript 中作用域、执行上下文、不同作用域下变量提升与函数提升的表现、顶层对象以及如何避免创建...

    lmxdawn 评论0 收藏0
  • JavaScript声明变量详解

    摘要:命令用于规定模块的对外接口,命令用于输入其他模块提供的功能所以在一定程度上来说,也具有声明变量的功能。当没有声明,直接给变量赋值时,会隐式地给变量声明,此时这个变量作为全局变量存在。 前言 如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过 在ES5阶段,JavaScript 使用 var 和 function 来声明变量, ES6 中又添加了let、const、imp...

    paulquei 评论0 收藏0
  • 详解JavaScript函数模式

    摘要:函数表达式又名匿名函数为变量赋的值是函数定义本身。在语言里任何匿名函数都是属于对象。这种情况下,就叫做回调函数。如上面代码示例展示了文档单击事件时以冒泡模式传递给回调函数的特别适用于事件驱动编程,因为回调模式支持程序以异步方式运行。 JavaScript设计模式的作用是提高代码的重用性,可读性,使代码更容易的维护和扩展 在javascript中,函数是一类对象,这表示他可以作为参数传递...

    wwolf 评论0 收藏0
  • 详解js变量声明提升

    摘要:换句话说,在代码执行之前,会对作用域链中所有变量和函数声明先处理完先。总结一句话就是只有声明被提升,而赋值或其他运算会留在原地。为其声明变量隐性劫持到所在区域中。 之前一直觉会认为javascript代码执行是由上到下一行行执行的。自从看了《你不知道的JS》后发现这个观点并不完全正确。先来给大家举一个书本上的的例子: var a=hello world; var a; co...

    NSFish 评论0 收藏0
  • ES6语法详解(一)

    摘要:冻结对象可以使用方法。对象的解构赋值必须要属性名相同,顺序毫无影响。数组解构赋值默认值,当等号右边的值时,默认值生效。 let变量 let声明的变量在let命令所在的代码块中有效。不存在变量提升,只能先声明后使用。 暂存死区 如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量。 var a = 1; { ...

    wendux 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<