JavaScript解析机制之变量提升
1、什么是预解析?
在当前作用域下,JS 运行之前,会把带有 var 和 function 关键字的事先声明,并在内存中安排好。(这个过程也可以理解为变量提升)然后再从上到下执行 JS 语句(预解析只会发生在通过 var 定义的变量和 function 上)
2、var 声明的变量
使用 var 声明的变量预解析:告诉解析器知道有这个名字的存在并默认将该变量赋值 undefined ,如下:
console.log(x); //undefined
var x = 5;
变量 x 虽然是在 console.log 后面定义的,但使用 var 申明的 x 会提前保存在内存中,并赋值 undefined ,然后再从上往下执行 JS 语句 。它的执行顺序类似于下面的结构:
var x;
console.log(x); //undefined
x = 5;
先声明了 x,x 没有定义所以赋值为 undefined ,输出的结果自然为 undefined,然后再给 x 赋值为 5
需注意的是,如果变量声明没有使用 var,则不存在变量提升。如下:
console.log(x); //error: x is not defined
x = 5;
x 没有使用 var 声明,所以报错找不到 x
3、functin 声明的函数
使用 function 声明函数的预解析:先告诉解析器这个函数名的存在,然后在告诉解析器这个函数名的函数体是什么,如下:
console.log(f);
function f() {
console.log("123");
}
声明函数会把整个函数都提升到最前面 ,所以浏览器中结果会输出整个函数,结果如下:
function f() {
console.log("123");
}
如果在一个函数作用域中声明一个变量 ,那么它也会提升到函数作用域的最上面,如下:
var x = 5;
function f() {
console.log(x); // undefined
var x = 2;
}
f();
以上虽然全局作用域声明了一个变量 x,但函数里也声明了一个变量 x,所以会先查找函数里面是否有变量 x,如果有就不会在全局下查找了。函数里面的变量 x 会被提升到函数作用域的最前面 ,并且赋值为 undefined,所以输出结果为 undefined ,类似于如下结构:
var x = 5;
function f() {
var x;
console.log(x); // undefined
x = 2;
}
f();
函数的参数也可以理解为函数作用域的变量 ,如下:
var x = 5;
function f(x) {
console.log(x); // undefined
}
f();
console.log(x); //
为函数 f 传递一个形参 x,由于函数在调用时没有传递实参(也就是说变量 x 没有赋值),所以为 undefined 。而在全局下输出 x 自然在全局下查找变量 x ,结果为 5
4、函数优先
变量声明和函数声明都会被提升,如果同一个作用域下声明的两个相同变量或相同函数,后一个会覆盖前一个,如下:
var x = 5;
var x = 10;
console.log(x); //
function f() {
console.log("xx");
}
function f() {
console.log("yy");
}
f(); // yy
但有一个需要注意的细节,如果声明的变量与函数名相同 ,那又会怎么覆盖呢?可以看如下例子:
var f = 5;
function f() {
console.log("xx");
}
f(); // error: f is not a function
JavaScript 中,函数的预解析优先级是要高于变量的预解析的。无论函数在什么位置声明,都优选把整个函数提升到最前面。所以上面的例子中,虽然函数 f 是在变量 f 下面定义的,但是在预解析时先解析函数 f,然后再解析变量 f,后面的变量 f 会把前面的函数 f 覆盖,最后 f 为 5 为数值类型,所以调用 f 时报错,f 不是一个函数。
需要注意的是 ,如果变量 f 定义后没有赋值 ,那么函数 f 就不会被覆盖了,如下:
var f;
function f() {
console.log("xx");
}
f(); // xx
所以函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
掌握以上知识,我们看下面的例子 :
console.log(x); // function x() {console.log(5);}
var x = 2;
console.log(x); //
function x() {
console.log(3);
}
console.log(x); //
var x = 3;
console.log(x); //
function x() {
console.log(5);
}
console.log(x); //
x(); // error: x is not a function
以上例子,两个函数 x 优先提升,所以第二个函数 x 覆盖第一个函数 x,然后两个变量 x 提升,由于变量 x 提升后为 undefined,所以第二个函数没有被覆盖,第一个输出 x 结果为第二个函数 function x(){console.log(5);}
随后 x 被赋值为 2 ,所以第二个输出 x 结果为 2
因为第一个函数 x 已经被提升到前面去了,所以第三个输出 x 结果还是 2
随后为 x 赋值为 3,所以第四,第五输出 x 结果为 3。最后调用 x,x 因为是数值类型,所以会报错 x 不是一个函数
我的博客也会同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=e1ebv5s48l8j
JavaScript解析机制之变量提升的更多相关文章
- javascript解析机制——预解析
JavaScript解析机制是什么? JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段. * 编译阶段 编译阶段就是我们常说的JavaScript预解析( ...
- 轻松搞定javascript变量(闭包,预解析机制,变量在内存的分配 )
变量: 存储数据的容器 1.声明 var 2.作用域 全局变量. 局部变量. 闭包(相对的全局变量): 3.类型 a.基本类型(undefi ...
- JavaScript系列文章:变量提升和函数提升
第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...
- JavaScript中函数的变量提升问题
函数的大体分三种,一种是函数的声明,一种是函数表达式(又称为函数的字面量) 1.函数的声明 => function myFn(){}; 2.函数的表达式 => var myFn = fun ...
- JavaScript 预编译(变量提升和函数提升的原理)
本文部分内容转自https://www.cnblogs.com/CBDoctor/p/3745246.html 1.变量提升 console.log(global); // undefined var ...
- javascript解析机制、闭包详解
js解析机制: js代码解析之前会创建一个如下的词法环境对象(仓库):LexicalEnvironment{ } 在扫描js代码时会把: 1.用声明的方式创建的函数的名字: 2.用var定义的变量的名 ...
- JavaScript解析机制与闭包原理实例详解
js代码解析机制: js代码解析之前会创建一个如下的词法环境对象(仓库):LexicalEnvironment{ } 在扫描js代码时会把: 1.用声明的方式创建的函数的名字; 2.用var定义的变量 ...
- JavaScript中的各种变量提升(Hoisting)
首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...
- JavaScript解析顺序和变量作用域
JavaScript基础之变量作用域. 一. 1.全局变量:全局变量的意思就是,在代码的不论什么地方都能够訪问到.注意:未定义 直接赋值的变量拥有全局属性. 2.局部变量:局部变量的意思就是,变量的作 ...
随机推荐
- [LeetCode] 499. The Maze III 迷宫 III
There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
上篇博文[SSH进阶之路]Hibernate映射——一对多关联映射(七),我们介绍了一对多关联映射,它是多对多关联映射的基础. 多对多映射是现实生活中最常见的映射,也是最容易理解的映射.废话少说,直接 ...
- Kubernetes 配置管理 Dashboard(十三)
目录 一.安装配置 1.1 下载 镜像 1.2.安装 1.3.修改 NodePort 二.配置授权 Kubernetes 所有的操作我们都是通过命令行工具 kubectl 完成的.为了提供更丰富的用户 ...
- Kubernetes 之 MySQL 持久存储和故障转移(十一)
目录 一.规划 二.部署 1.创建 PV 和 PVC 2.部署 MySQL 3.更新 MySQL 数据 4.故障转移 一.规划 我们接着之前的文档的架构规划进行下面的操作. IP 角色 192.168 ...
- SpringBoot系列教程JPA之delete使用姿势详解
原文: 190702-SpringBoot系列教程JPA之delete使用姿势详解 常见db中的四个操作curd,前面的几篇博文分别介绍了insert,update,接下来我们看下delete的使用姿 ...
- ztree取消之前选中状态并设置新的选中
var zTreeObject = $.fn.zTree.getZTreeObj("treeId"); var node = zTreeObject.getNodeByParam( ...
- python的进修之路
PYTHON目录篇 本篇主要在个人学习python中的一些总结性的总线,包括python的基础,python的基础进阶,除了帮助和我一样学习python的同学,也是对自己的一种要求! python基础 ...
- PAT(B) 1090 危险品装箱(Java)
题目链接:1090 危险品装箱 (25 point(s)) 题目描述 集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里.比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸. 本题 ...
- Ubuntu 中linux 编译错误的(-)
1.错误 compress.c:14:58: fatal error: zlib.h: No such file or directorycompilation terminated. 解决:sudo ...
- CCF 2016-04-1 折点计数
CCF 2016-04-1 折点计数 题目 问题描述 给定n个整数表示一个商店连续n天的销售量.如果某天之前销售量在增长,而后一天销售量减少,则称这一天为折点,反过来如果之前销售量减少而后一天销售量增 ...