javaScript变量提升以及函数提升

变量的声明赋值

var a = 1;

上面的代码先声明变量 a,然后在变量 a 与数值 1 之间建立引用关系,称为将数值 1 “赋值”给变量 a。以后,引用变量名 a 就会得到数值 1。最前面的 var,是变量声明命令。它表示通知解释引擎,要创建一个变量 a

  • 实际变量的声明和赋值,是分开的两个步骤,如下
var a;
a = 1;
  • 如果只是声明变量而没有赋值,则该变量的值是 undefinedundefined 是一个特殊的值,表示“无定义”。
var a;
a // undefined
  • 没有写 var 去声明变量,不写 var 的做法,会创建全局变量, a = 1 等同于 window.a = 1
var a = 1;
// 基本等同
a = 1;

多次声明,后者会覆盖前者

什么是变量提升

直觉上会认为 JavaScript 代码在执行时是由上到下一行一行执行的。但实际上这并不完全正确,有一种特殊情况会导致这个假设是错误的。

示例如下

  • 考虑以下代码:
a = 2;
var a;
console.log(a);

console.log(..) 声明会输出什么呢?

很多人会认为是 undefined,因为 var a 声明在 a = 2 之后,他们自然而然地认为变量被重新赋值了,因此会被赋予默认值 undefined。但是,真正的输出结果是 2

  • 考虑另外一段代码:
console.log(a);
var a = 2;

你可能会认为这个代码片段也会有同样的行为而输出 2。还有人可能会认为,由于变量 a 在使用前没有先进行声明, 因此会抛出 ReferenceError 异常。不幸的是两种猜测都是不对的。输出来的会是 undefined

为什么会出现这种情况?
JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。
这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,而赋值或其他运行逻辑会留在原地,这就叫做变量提升
包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理,这种现象称为提升。

变量声明提升:

  • JavaScript 的变量提升是针对 var 的,而 letconst 不存在变量提升这一特性(letconst 具有一个临时死区的概念)
  • 通过 var 定义的变量,在定义语句之前就可以访问到 值:undefined
  • 变量提升就是变量会被提升到作用域的最顶上去,也就是该变量不管是在作用域的哪个地方声明的,都会提升到作用域的最顶上去。
  • JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined
  • 如果变量一直都没有声明过,则会抛出 ReferenceError,比如直接输出:console.log(b) // Uncaught ReferenceError: b is not defined
  • 当你看到 var a = 2; 时,可能会认为这是一个声明。但 JavaScript 实际上会将其看成两个声明:var a;a = 2;。
    • 第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段
    • 处理如下
a = 2;
var a;
console.log(a);
// 上面这段代码会被 js 处理成如下代码
var a;
a = 2;
console.log(a);

函数声明提升

  • JavaScript 引擎将函数名视同变量名,所以采用 function 命令声明函数时,整个代码块会提升到它所在的作用域的最开始执行
  • 通过 function 声明的函数,在之前就可以直接调用
  • 函数提升只会提升函数声明,而不会提升函数表达式。
fx() // fx is a great girl 之前之后都可调用
function fx () {
  console.log('fx is a great girl')
}
fx() // fx is a great girl 之前之后都可调用
  • 函数表达式声明的函数
console.log(fx) // undefined
var fx = function () {
  console.log('fx is a great girl')
}

// ======================

fx() // 不是 ReferenceError, 而是 TypeErr
var fx = function () {
  console.log('fx is a great girl')
}

这段程序中的变量标识符 fx() 被提升并分配给所在作用域(在这里是全局作用域),因此 fx() 不会导致 ReferenceError
但是 fx 此时并没有赋值(如果它是一个函数声明而不是函数表达式,那么就会赋值)。fx() 由于对 undefined 值进行函数调用而导致非法操作, 因此抛出 TypeError 异常。

函数声明和变量声明使用同一个变量名称

函数的优先级高于变量的优先级

// 会输出fx定义的函数
console.log(fx)
function fx () {
  console.log('fx is a great girl')
}
var fx = 'fx'
console.log(fx) // fx

多个同名函数声明

由最后面的函数声明来替代前面的

fx() // fx is a great girl
function fx () {
  console.log('fx')
}
function fx () {
  console.log('fx is a great girl')
}

示例

示例一

每个作用域都会进行提升操作

var a = 100
function fn () {
    console.log(a)
    var a = 200
    console.log(a)
}
fn()
console.log(a)
var a
console.log(a)
var a = 300
console.log(a)

这段代码将会依次输出 undefined 200 100 100 300

fn() 函数中由于声明了 var a = 200, 所以 var a 会被提升到 fn 的作用域顶端,第一输出则为 undefined

示例二

下面这段代码,由于 es6 之前,js 是没有块级作用域的,所以 if 中声明的 a 变量会被当成全局变量处理

var a = 1
if (true) {
    var a = 2
}
console.log(a) // 2

示例三

var a = 10                        
function fx () {
    console.log(a) // undefined
    var a = 20
    console.log(a) // 20
}
fx()
console.log(a) // 10

// ===

var a = 10
function fx () {
    console.log(a) // 10
    a = 20
    console.log(a) // 20
}
fx()
console.log(a) // 20

第二段代码 fx() 中的 a 没有使用 var 定义,会造成 fx 函数中没有变量声明,所以 fx 里面访问的变量 a,其实都是访问的全局变量 aa = 20 又相当于给全局变量 a 重新赋值 20

示例四

即使 if 语句的条件是 false,也一样不影响 a 变量提升

function fx () {
    console.log(a) // undefined
    if (false) {
        var a = 1
    }
    console.log(a) // undefined
    console.log(b) // Uncaught ReferenceError: b is not defined
}
fx()

示例五

function fx () {
    console.log('fx is a great girl')
}
var fx
console.log(typeof fx) // function

// =======================

function fx () {
    console.log('fx is a great girl')
}
var fx = 'good girl'
console.log(typeof fx) // string

// =======================

console.log(typeof fx) // function fx(){}函数提升
var fx = 'good girl'
function fx () {
    console.log('fx is a great girl')
}
console.log(typeof fx) // string

// =======================

console.log(typeof fx) // function
var fx
function fx () {
    console.log('fx is a great girl')
}
console.log(typeof fx) // function

示例六

if(!(fx in window)) {
    var fx = 1
}
console.log(fx) // undefined

示例七

var c = 1
function c(c) {
	console.log(c)
}
c(2) // c is not a function
 
// ========
 
c(2) // 2
var c = 1
function c(c) {
	console.log(c)
}
console.log(c) // 1
// ========
 
var c = function(c) {
	console.log(c)
}
c(2) // 2
var c = 1
 
// ========
var c = function(c) {
	console.log(c)
}
var c = 1
c(2) // Uncaught TypeError: c is not a function
 
// ========
 
c(2) // Uncaught TypeError: c is not a function
var c = function(c) {
	console.log(c)
}
var c = 1
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wflynn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值