[JavaScript]何为变量提升?

news/2024/10/1 21:45:34

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://www.cnblogs.com/cnb-yuchen/p/18252500
出自【进步*于辰的博客】

关于编译与解释,详述可查阅博文《[Java]知识点》中的【编译与解释】一栏。
参考笔记二,P43.3、P46.1、P9.3。

目录
  • 附言
  • 1、介绍
  • 2、解答
  • 3、一种特殊情况
  • 最后

附言

你在阅读本篇文章时,会看到一些名词,如:函数作用域,也就是由 var 声明的变量的作用域的名称,它是我根据我的理解自定义的。后来我了解到,JS中似乎并没有这个概念,对应的概念好像是“词法作用域”。

我暂未系统地学习JS,故无法详细地为你说明这个概念。当然,尽管我的用词可能不对,但就目前,这有助于我的学习理解。

如果你想进一步地学习这方面的知识,推荐一篇博文《JavaScript执行机制:变量提升、作用域链、词法作用域、块级作用域、闭包和this》(转发)。

1、介绍

什么是“变量提升?

“变量提升”是指在解释时,解释器先扫描整个JS脚本,将所有声明(包括变量和函数)移动到作用域顶端的机制,其本质就是声明与定义不同步的错觉。

var 与 let 具有相同的变量提升机制,故经变量提升后(“解释”后)的脚本相同。

PS:大家可能不明其意,往下看。

先说说两种修饰符声明变量的作用域的定义:

  1. var:作用域的“上界”是变量声明处“往上”的第一个函数花括号({),故也称为“函数作用域”。var 允许重复声明和定义。
  2. let:作用域的“上界”是变量声明处“往上”的第一个花括号({).,故也称为“块级作用域”。let 不允许重复声明和定义(同一作用域)。

let 与 var 不同的是,let 声明的变量在定义之前,存在“暂时性死区”,

示例:

console.log(str)
let str = 1

输出结果:
在这里插入图片描述
因为示例代码经“变量提升”后:

let str
console.log(str)
str = 1

这就是“暂时性死区”,在定义前访问或赋值会报错。如:let str是声明,let str = 1是定义。

2、解答

1:如何理解“函数的变量提升优先于变量?”(PS:一些资料中可能会这样阐述)

事实上,之前由于我的JS功底不够扎实,也误解了这句话,以为是这样:

console.log(b)
var a = 1
var b = function() {return 2
}

经变量提升后:

var b
var a
console.log(b);// undefined
a = 1
b = function() {return 2
}

如果真的如我之前这般理解,无意义,并且也理解错误。

那么,“函数的变量提升优先于变量”这句话到底是什么意思?我从博文《JavaScript执行前的秘书——预编译》(转发)中取经得知,如下:

console.log(b)
var a = 1
function b() {return 2
}

经变量提升后:

function b() {return 2
}
var a
console.log(b);// [Function: b]
a = 1

所以,我之前是把var b = function() {}的形式误解为"函数声明”,实际上,这也是“变量声明”,只是变量值定义为函数而已。

最后,引用一段“取经”博文中的阐述:
在这里插入图片描述

2:如何解释“let 不允许重复声明和定义”?

我们先来看由 var 修饰的情况,示例:

var a = 1
var a = 2

经变量提升后:

var a
a = 1
a = 2

也就是:变量提升会将重复声明进行覆盖

再来看 let 的情况。如果两个同名的变量都由 let 修饰,报错,这是 let 的特性。大家疑惑的多是这种情况:

var a = 1
let a = 2

先解答:也会报错。为什么?这涉及到一个细节:

var 的变量提升的优先级高于 let。

也就是说,经变量提升后:

var a
let a
a = 1
a = 2

这种情况 let 同样不允许,故报错。

稍作修改:

let a = 1
var a = 2

这种情况与上述完全相同,故也不允许。

3、一种特殊情况

在上文中,我们说到,这种情况不允许:

var a = 1
let a = 2

那么,请问下面这种情况能正常执行吗?

var a = 1
{----------------------Alet a = 2
}

要解决这个问题,就要研究 var 与 let 的作用域了,大家还记得我在上文中所述的它们的作用域的定义吗?结论:

第一个a的作用域是“全局”,而第二个a的作用域是 A 处的代码块。

因此,两个a的作用域不同,故不报错。

再给大家抛出一个问题:这样会报错吗?

let a = 1
{var a = 2
}

PS:相信大家看到这里,已经对 var 和 let 有了足够的掌握,这个问题就交由大家思考了。

最后,为大家补充两个结论:

  1. var 是ES5的语法,let 是ES6的语法。
  2. 定义变量时可以不用 var 或 let 修饰(即直接a = 1),那么 var 与 let 的作用是什么?var 与 let 定义 / 决定了变量的作用域。因此,定义变量时如果不用 var 或 let 修饰,就不存在“变量提升”,则在定义前访问或赋值将直接报错。

最后

其实,在日常工作中,区分var与lei的实际作用并不大,我们更关注的是业务的梳理。因此,本篇文章旨在巩固JS基础。

还有,const也会“变量提升”,如let一般,具有块级作用域。

本文完结。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44963.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

第一章 递归问题 学习笔记

河内塔问题有 \(3\) 根柱子和 \(n\) 个圆盘,我们可以把最顶上的圆盘移到另外的柱子上,但不可以把大的圆盘放在小的圆盘上面 问,最少需要多少步才能把所有圆盘从一根柱子移到另外一跟柱子上 我们先命名一个状态 \(T_n\) 表示圆盘从一根柱子移动到另外一根柱子的最少次数 那么…

uniapp 实现个人信息的修改

今天设计用户界面和用户基本信息设计页面,完成登录后用户的信息就会显示在此页面,然后进入修改页面后就可以对用户的对应信息进行修改。<template><view class="container"><view class="profile"><image :src="userInfo.head…

uniapp 随机抽取视频播放

编写了一个视频播放界面,然后再从后端再随机读取10条视频信息,最后在我们前端app的页面上显示出来。<template><view class="index"><transition name="fade"><view class="video-container" @touchstart="touchSta…

uniapp手机号认证注册的一个页面

今天主要在uniapp设计了一个通过手机号认证注册的一个页面,但是今天只完成了前端页面的部分。并且能成功的连接上对应的后端地址。<template><view class="container"><view class="logo"><!-- 这里放置你的应用 logo --><ima…

增补博客 第二十九篇 计算机网络复习四

第五章 运输层 1.运输层的作用 运输层向它上面的应用层提供通信服务(提供端到端,进程到进程的可靠通信),为运行在不同host上的进程提供逻辑通信,向高层用户屏蔽通信子网的细节 2.UDP和TCP的特点,及使用它们的应用程序,熟知端口号 UDP和TCP的特点:UDP支持单播、多播、广…

LeetCode 633 Sum of Square Numbers All In One

LeetCode 633 Sum of Square Numbers All In One 633. Sum of Square Numbers Math.sqrt Math.trunc Math.powLeetCode 633 Sum of Square Numbers All In OneSum of Square NumberssolutionsMath.sqrt / 平方根function judgeSquareSum(c: number): boolean {let max = Math.t…

又跳槽!3年Java经验收割成都大厂的面试心得(干货满满文末有福利)

中厂->阿里->字节,成都->杭州->成都 系列文章目录和关于我 0.前言 笔者在不足两年经验的时候从成都一家金融科技中厂跳槽到杭州阿里淘天集团,又于今年5月份从杭州淘天跳槽到成都字节。自认为自己在面试这方面有一点心得,处于记录和分享的目的便有了此文,此文纯…