前两天遇到的问题,经过很多网友的深刻讨论,终于有一个相对可以解释的通的逻辑了,然后我仔细研究了一下相关的点,顺带研究了一下js中的隐式变量。

  • 以下文章中提到的隐式变量都是指没有用var,let,const等关键字定义的变量。
  • 以下文章中提到的var变量都是指用var声明定义的变量。

一遇到隐式变量,我们去百度一下,都会看见这样一句话,隐式变量是全局变量,在函数中用隐式变量也是全局变量,但是在函数中用var变量是局部变量,那我们来具体看下隐式变量到底与var变量有什么区别,下面我们来通过一些代码来探究隐式变量与var变量的区别。

1.隐式变量与var变量的区别

代码1:

var变量:

console.log(a);//undefined
var a = 100;

代码2:

隐式变量:

console.log(a);//Uncaught ReferenceError: a is not defined
a = 100;

看上面的代码我们发现var变量a是存在变量声明提升的,也就是代码1相当于下面的代码:

var a;
console.log(a);
a = 100;

这与我们以前了解的那个var变量是一样的,变量声明提升还是那个变量声明提升,并不会改变,这里如果想详细了解变量提升的,推荐这篇文章大家可以看一下。然后我们继续看代码2,隐式变量在前面打印变量a时会报错,那这里我们是不是可以猜测,隐式变量是不是不存在变量提升,当然以前好像也没有人说过隐式变量存在声明提升,可能我一厢情愿的认为隐式变量是全局变量就存在声明提升。然后我们继续看在函数中,代码块中声明的隐式变量是不是跟上面全局定义的隐式变量一样,不存在声明提升。

代码3:

函数中的var变量:

console.log(a);//Uncaught ReferenceError: a is not defined
function b() {
console.log(a);//undefined
var a = 100;
}
b(); 

代码4:

函数中的隐式变量:

console.log(a);//Uncaught ReferenceError: a is not defined
function b() {
console.log(a);//Uncaught ReferenceError: a is not defined
a = 100;
}
b();

我们来看上面的代码3和代码4,我们发现代码3,在第一行就报错,因为var在函数内部定义的变量属于局部变量,全局是访问不到的,然后把第一行注释掉再运行,发现第三行打印出的a是undefined,证明var变量在函数中进行了变量声明提升。我们来看代码4,在函数内定义了一个隐式变量,然后第一行就会报错,a是未定义,然后把第一行注释掉再运行,发现第三行也还是报错a未定义,这里是不是就说明隐式变量并不会有变量声明提升这种操作,换一句话说,就是隐式变量类似于函数一样,声明和定义是一起的,只有执行了这行代码,才能引用访问这个变量,这里推荐一篇关于变量生命周期的文章,可以细读一下,然后我们再看一下代码块中定义的var变量和隐式变量:

代码5:

代码块中的var变量:

console.log(a);//undefined
{
console.log(a);//undefined
var a = 100;
}

代码6:

代码块中的隐式变量:

console.log(a);//Uncaught ReferenceError: a is not defined
{
console.log(a);//Uncaught ReferenceError: a is not defined
a = 100;
}

然后我们看代码块中的var变量,是存在声明提升的,然后隐式变量是不存在声明提升的,所以上面访问都会报错。

  • 结论:根据上面的一系列的探究我们基本可以确定一个结论,那就是隐式变量是不存在变量声明提升的。

2.代码块中的函数声明提升

上面探究完隐式变量我们再稍微看下代码块中的函数声明提升:

代码7:

console.log(a);//undefined
{
function a(){};
console.log(a);//ƒ a(){}
}
console.log(a);//ƒ a(){}

我们看上面的代码,我们都知道函数是js中的"一等公民",优先级是最高的,那在上面这个代码中,函数是否提升到了块作用域的外面呢,如果我说提升了,那你从块作用域最外面调用你会发现报错,a不是一个方法:

a();//Uncaught TypeError: a is not a function
{
function a(){};
}

然后这样之前的我就得出一个结论,函数声明提升并没有将函数提升到最外层,那就要问那上面我们打印的a为undefined,为什么不是报错a未定义呢,根据阮一峰老师的这篇文章的描述,我们可以得出一个结论:

  • 块作用域内定义的函数在块作用域内会进行函数提升,提升到最上面,然后在最外层类似于var声明一个同名变量,默认值为undefined。

3.代码块中存在同名的隐式变量与函数的情况

然后我们再回过头来看代码块中同时存在同名的隐式变量和函数时会怎样:

首先我们来看上面这个代码,此时如果我们再最外层的上面打印a和b你会发现会打印出来是undefined:

代码8:

console.log(a,b);//undefined undefined
{
console.log(a);//ƒ a() {}
function a() {};
a = 50;
console.log(a);//50
}
console.log(a);//ƒ a() {}
{
console.log(b);//ƒ b() {}
b = 50;
function b() {};
console.log(b);//50
}
console.log(b);//50

我们看上面的代码,你会发现最前面打印a和b都是undefined,通过前面对隐式变量和函数声明的探究我们可以知道此时外面的a和b都是函数声明定义的,另外我们从侧面也可以看出这一点,vscode有一个功能,是可以查看变量是谁定义的,那我们来看一下:

此时我们发现vscode分析出来最上面的a和b都是a和b函数定义的,根据我们上面的探究,既然隐式变量不存在变量声明提升,那只能函数定义的,然后通过对函数的探究可以证实这一点,同时配上vscode分析出来的结果,也证实了这一点,首先可以确定,最外层的全局的a和b都是函数定义的。然后我们再继续往下看,最开始的a和b打印undefined没问题,

然后我们来看下上面图片上第16行打印的结果为什么是a方法,通过我上篇文章一行一行的调试你会发现,此时代码块中的a其实是被限制在块作用域里面的,并不是全局的变量,此时其实a = 50这行代码不是隐式变量,因为a已经被函数定义过了,那a = 50也就是对之前定义过的变量赋值了,所以此时

a = 50不是隐式变量,然后对之前定义的a赋值,在代码块中打印出来为50,然后出了块作用域打印出来的结果为方法a,通过代码一步步的调试你会发现全局的a,只有在执行a方法的代码时才会把块作用域赋的值同步到全局。

第一步:此时全局的a为undefined,此时a是代码块中函数定义的:

第二步:此时我们发现出来了一个块作用域,因为代码块中的函数提前了,此时代码块中的a的值为a方法,而全局的a还是undefined,没什么问题

第三步:此时我们会发现当函数a这一行代码走完之后,块作用域里面的a跟全局的a都变成了a方法,也就是说想要让块作用域中的a的值同步到全局,必须让代码执行到定义a方法的下一行才可以,要不然代码块中的a的值是不会同步到代码块外面的

第四步:到这一步我们会发现块作用域中的a变成了50,而全局的a还是a方法,根据上一步得到的结论,此时只要在a = 50这行代码后面再执行一次方法a,a = 50就会被同步到全局,此时验证一下也确实是这样

然后出块作用域你会发现打印a为a方法,此时你就不会好奇为什么打印结果是a方法了,因为块作用域中的a并没有同步到全局,而b打印50,是因为b = 50后面执行了一行b方法,将b同步到了全局。到这里我们也就了解为什么两个代码只是换了一下函数的位置打印结果过就完全不同了,然后看文章的时候如果发现有什么错误或写的不好的地方,还请指正,我会立即做出修改。

深入探究js中的隐式变量声明的更多相关文章

  1. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  2. EL表达式中引用隐式变量

    除了在jsp中9大隐式变量(在前面文章也叫预定义变量)在转化成为servlet后_jspService中可以看到: public void _jspService(final javax.servle ...

  3. c语言中的隐式函数声明(转)

    本文转自:http://www.jb51.net/article/78212.htm 在c语言里面开来还是要学习c++的编程习惯,使用函数之前一定要声明.不然,即使编译能通过,运行时也可能会出一些莫名 ...

  4. 万恶之源:C语言中的隐式函数声明

    1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自己主动依照一种隐式声明的规则,为调用函数的C代码产生汇编代码.以下是一个样例: int main(i ...

  5. Js 中那些 隐式转换

    曾经看到过这样一个代码:  (!(~+[])+{})[--[~+""][+[]]*[~+[]]+~~!+[]]+({}+[])[[~!+[]*~+[]]] = sb , 你敢相信, ...

  6. js中的隐式转换

    js中的不同的数据类型之间的比较转换规则如下: 1. 对象和布尔值比较 对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字 [] == true; //false [] ...

  7. Scala 中的隐式转换和隐式参数

    隐式定义是指编译器为了修正类型错误而允许插入到程序中的定义. 举例: 正常情况下"120"/12显然会报错,因为 String 类并没有实现 / 这个方法,我们无法去决定 Stri ...

  8. javascript中的隐式类型转化

    javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对 ...

  9. C#中的隐式转换

    你是否考虑过这个问题:为什么不同类型之间的变量可以赋值,而不需要强制转换类型?如: int i = 1; long l = i; object obj = 1; Exception exception ...

随机推荐

  1. HDU 6315

    题意略. 思路:本题的思路总的来说就是暴力 + 剪枝. 我们依然用线段树来维护: 定义结点node{ l , r , minn , contirbute} 分别为某个区间的左右端点,和该区间(b序列) ...

  2. HDU - 3416-Marriage Match IV (最大流 + 最短路)

    HDU - 3416:http://acm.hdu.edu.cn/showproblem.php?pid=3416 参考:https://www.cnblogs.com/kuangbin/archiv ...

  3. Minimum spanning tree for each edge(倍增LCA)

    https://vjudge.net/contest/320992#problem/J 暑期训练的题. 题意:给你一个n个点,m条边的无向图.对于每一条边,求包括该边的最小生成树. 思路:首先想到求一 ...

  4. CodeForces 982 C Cut 'em all!

    Cut 'em all! 题意:求删除了边之后,剩下的每一块联通块他的点数都为偶数,求删除的边最多能是多少. 题解:如果n为奇数,直接返回-1,因为不可能成立.如果n为偶数,随意找一个点DFS建树记录 ...

  5. Python---网络爬虫初识

    1. 网络爬虫介绍 来自wiki的介绍: 网络爬虫(英语:web crawler),也叫网上蜘蛛(spider),是一种用来自动浏览万维网的网络机器人. 但是我们在写网络爬虫时还要注意遵守网络规则,这 ...

  6. 02 python 必知

    一.变量 1.变量的定义 将程序运算的中间结果临时存在内存里,以便后续代码调用. 2.变量的使用规范 1)变量必须要有数字,字母,下划线,任意组合. 2)变量不能数字开头. 3)不能是python中的 ...

  7. 封装axios来管控api的2种方式

    前言:我们在开发项目的时候,往往要处理大量的接口.并且在测试环境 开发环境 生产环境使用的接口baseurl都不一样 这时候如果在开发环境完成之后切换每一个接口的baseurl会变的非常的麻烦,(要去 ...

  8. 小白的消费为何被迫升级?-java数据类型的转换

    背景 小白最近有点烦恼,原因也很简单,不知道为何?小白的消费不知不觉被迫升级了,请看费用清单: for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; ...

  9. Quartz技术原理

    Quartz运行基本: (1)       创建任务jobDetail(放入具体的jobImpl),触发器trigger(保存job的触发策略),均放入调度器scheduler. (2)       ...

  10. Hive入门--2.分区表 外部分区表 关联查询

    1.查看mysql中metastore数据存储结构 Metastore中只保存了表的描述信息(名字,列,类型,对应目录) 使用SQLYog连接itcast05 的mysql数据库  查看hive数据库 ...