深入浅出JS - 变量提升(函数声明提升)

news/2024/7/5 4:53:27

前言

在我们的日常工作中,变量无处不在。更加深入的去了解它,能够使得自己的JS水平更上一层楼, 从变量提升这个小知识点着手,让我们一起来深入了解JS吧!

变量提升的小栗子

console.log(a) // undefined
var a = 'hello JS' 

/* 在我们声明a之前为什么输出a不会报错呢? 不急,让我们接着往下看 */

num = 6;
num++;
var num;
console.log(num) // 7 好奇怪,为什么给一个还没有声明的变量赋值会不报错呢

function hoistFunction() {
    foo();
    function foo() {        
        console.log('running...')    
    }
}
hoistFunction(); // running... 

/* 最后一个栗子 */

alert(a) //  function a { alert(10) }
a(); // 10
var a = 3;
function a() {    
    alert(10)
};
alert(a) // 3
a = 6;
a(); // throw error复制代码


分析原因

JS引擎会在正式执行代码之前进行一次”预编译“,预编译简单理解就是在内存中开辟一些空间,存放一些变量和函数。具体步骤如下(browser):

  • 页面创建GO全局对象(Global Object)对象(window对象)。
  • 加载第一个脚本文件
  • 脚本加载完毕后,进行语法分析。
  • 开始预编译
    • 查找函数声明,作为GO属性,值赋予函数体(函数声明优先)
    • 查找变量声明,作为GO属性,值赋予undefined
    • GO/window = {
          //页面加载创建GO同时,创建了document、navigator、screen等等属性,此处省略
          a: undefined,
          c: undefined,
          b: function(y){
              var x = 1;
              console.log('so easy');
          }
      }复制代码
  • 解释执行代码(直到执行函数b,该部分也被叫做词法分析
    • 创建AO活动对象(Active Object)
    • 查找形参和变量声明,值赋予undefined
    • 实参值赋给形参
    • 查找函数声明,值赋给函数体
    • 解释执行函数中的代码

      GO/window = {
          //变量随着执行流得到初始化
          a: 1,
          c: function(){
              //...
          },
          b: function(y){
              var x = 1;
              console.log('so easy');
          }
      }
      复制代码
  • 第一个脚本文件执行完毕,加载第二个脚本文件
  • 第二个文件加载完毕后,进行语法分析
  • 开始预编译
    • 重复预编译步骤 ....

预解析机制使得变量提升(Hoisting),从字面上理解就是变量和函数的声明会移动到移动到函数或者全局代码的开头位置。我们再来分析一下小栗子加深一下理解。

console.log(a) // 执行之前,变量提升作为window的属性, 值被设置为undefined
var a = 'hello JS' 

/* JavaScript 仅提升声明,而不提升初始化 */

num = 6;
num++;
var num;
console.log(num) // 变量提升 值为undefined的num赋值为6,再自增 => 7

function hoistFunction() {
    foo();
    function foo() {        
        console.log('running...')    
    }
}
hoistFunction(); // 函数声明提升,可以在函数体之前执行

/* 最后一个栗子 */

alert(a) // 最后的声明为函数声明, 因此a此时为函数体
a(); // 执行 a 函数,输出10
var a = 3; // 3 赋给a
function a() {    
    alert(10)
};
alert(a) // 3
a = 6; // 6赋给a,不是一个函数,故下方执行throw error
a(); // throw error
复制代码

注: JS并不存在真正的预编译,var与function的提升实际是在语法分析阶段就处理好的。而且JS的预编译是以一个脚本文件为块的。一个脚本文件进行一次预编译,而不是全文编译完成再进行”预编译”的。


最佳实践 

理解了变量提升和函数提升可以使得我们在JS上走的更远,但是我们在开发中,不应该使用这一特性,而是要规范我们的代码,做到可维护性和可读性。无论是变量还是函数,都必须先声明后使用。PS:在开发中应该使用let来约束变量提升。


参考资料:  

https://developer.mozilla.org/zh-CN/docs/Glossary/Hoisting https://www.cnblogs.com/liuhe688/p/5891273.html http://dmitrysoshnikov.com/notes/note-4-two-words-about-hoisting/ https://segmentfault.com/a/1190000010187653






http://www.niftyadmin.cn/n/2607910.html

相关文章

图像增强序列——基于Lab色彩空间和色调映射的彩色图像增强算法

1. 参考文献2. 模型实现 % 论文: 基于Lab色彩空间和色调映射的彩色图像增强算法 % 作者: % 链接: http://www.jsjkx.com/jsjkxen/ch/reader/create_pdf.aspx?file_no20180251&year_id2018&quarter_id2&falg1 % Author: HSW % Date: 2018-04-26clc; clo…

移除input在type=number时的上下箭头

网页在有些情况下,会需要input的输入的为单纯数字的文本框,此时typenumber,但使用typenumber时,输入框后面会有一个上下箭头,那么如何去掉上下箭头呢? 1、chrome浏览器移除 input::-webkit-outer-spin-butt…

van-list immediate-check设置为false无效的问题

最近在使用van-list组件开发带有tab切换的项目,需求是tab是后端返回的数据,所以获取列表数据要在tab返回之后调用,所以进入页面时默认不触发van-list的load事件,官方文档说明:如下图所示: 组件配置如图所示…

图像增强序列——Adaptive Local Power-Law Transformation for Color Image Enhancement(自适应伽马变换)

1. 参考文献2. 模型实现 % 论文: Adaptive Local Power-Law Transformation for Color Image Enhancement % 作者: Chun-Ming Tsai % % Author: HSW % Date: 2018-04-27clc; close all; clear;img imread(timg2.jpg);figure(1); imshow(img, []); title…

element 验证出现英文以及自动验证问题

最近在项目开发中用到了element-ui框架&#xff0c;写了一套很长的表单提交&#xff0c;用到了el-form整这个组件&#xff0c;用这个组件的好处就是我们不用单独去做表单的校验&#xff0c;也省了一堆if条件判断&#xff0c;下面请看官方示例&#xff1a; <el-form :model&…

CentOS的常用快捷键

Centos常用快捷键: CentOS 6.4 中可以通过系统->首选项->键盘快捷键来设置快捷键&#xff0c;如图所示。例如可将运行终端的快捷键设为CtrlAltT。 Ctrl u 删除光标之前到行首的字符 Ctrl k 删除光标之前到行尾的字符 Ctrl c 取消当前行输入的命令&#xff0c;相当于Ct…

第四章-java多线程核心技术-Lock锁-第三篇

2019独角兽企业重金招聘Python工程师标准>>> Condition实现顺序运行 使用condition对象可以对线程业务进行规划和排序。请看如下代码 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock;public class Run {volatile p…

图像增强序列——LIME: A Method for Low-light IMage Enhancement(LIME模型,2017CVPR)

1. 参考文献2. 模型实现 % 论文&#xff1a; LIME: A Method for Low-light Image Enhancement % 作者&#xff1a;Xiaojie Guo % 链接&#xff1a; % Author: HSW % Date: 2018-04-27clc; close all; clear;addpath(genpath(removeHaze\)); addpath(genpath(BM3D\)); % img …