带你论证JS基础的一段代码

简介: 在学习乏味难啃的理论基础知识时,我觉得应该创造自己的想象力,多去实践多去思考为什么会有这样的结果呢?

JS基础对于我们前端开发的重要性不言而知~于是,我们都会选择去阅读一些书籍来充实自己。那当我们读完那些理论基础之后,你是否依旧迷茫,还是豁然开朗?

透过现象看本质!

我想:有了理论基础作为根据的时候,应该多去思考一些代码的结果来实践这些理论。

就比如解决bug一样,你总得先知道出现bug的原因,再根据原因去解决问题是一样的道理。

code案例

var b = 10;

(function b(){

b = 20;

console.log(b);

})();

这段代码会输出什么呢?

(ps:先别着急回答,好好思考一下)

乍一看,这段代码很简单,涉及到的内容是var function IIFE,好像也没什么问题。

这段代码的在严格模式下输出:TypeError: Assignment to constant variable

意思就是:类型错误:对常量变量的赋值

而在非严格模式下输出:

输出分析

分析严格模式下的输出如果由这个TypeError: Assignment to constant variable.做一个分析的话,那么意味着变量b是不可修改的!

那么现在的问题在于变量b是指外部用var声明的变量b呢,还是立即执行的具名函数b呢?

如果b是立即执行的具名函数名称,说实话我也不大确定它是否是可修改。

(ps:大多数的js书籍中都没有明确指出立即执行函数表达式是否能重新赋值的问题)

但是我一定可以确定的是,如果b是指外部用var声明的,那么在此代码中它一定是可修改的。我们都知道用var声明的全局变量它在任何地方肯定是可以修改的,因为该变量处于作用域的最顶端。

所以在这里我想大胆做个假设:变量b是指立即执行的具名函数名称b~

做完这个假设,我想说:

那意味着全局变量b在立即执行的具名函数b里访问不到吗?

其实不是的,全局变量b在立即执行的具名函数b是可被访问的,只不过因为具名函数b的内部作用域里也存在了一个用function声明的变量b,所以在代码执行的时候js引擎首先找到用function声明的变量b。正如书籍中讲到的作用域查询是通过从里到外向上查询。

(ps:之前也顺手写了一篇关于作用域系列的文章:我是这样理解JavaScript中作用域,望能帮助大家~)

当然在非严格模式下,大家可以试着动手在立即执行的具名函数内部函数打印一下window.b,也可论证全局变量b在立即执行的具名函数b里可被访问!代码如下:

var b = 10;

(function b(){

b = 20;

console.log(window.b);

})();

到这里,理清楚了立即执行函数b的内部作用域机制,我的疑问又萌生了:

为什么(function b(){}())这样的函数表达式就不能修改呢?

后来,我查阅了资料,明白了IIFE函数的内部机制~

我所理解的是:

当遇到具名的函数表达式的时,会创建一个辅助的特定对象,将函数表达式的名称作为唯一的key,用来存储函数表达式的名称,然后添加到函数的作用域链中,该值只读,并且不可以被删除,所以不能对该值进行操作。

所以,在严格模式下,一个不可修改的常量被修改之后就会报TypeError: Assignment to constant variable。

分析非严格模式的输出 在非严格模式下会静默失败,所以不报错。针对如上的分析之后,会输出立即执行的具名函数b本身。

code扩展

我将代码改写成:

var b = 10;

(function b(){

return 1;

})();

console.log(b);

那这段又会输出什么呢?

无论在非严格模式还是在严格模式下,这段代码都会输出10,也就是全局变量b的值~

写这段代码的本意并不是为了猜测结果而想的,我想表达的是:为什么立即执行具名函数b在外部是不可访问的?难道所有的表达式在外部都不可访问吗?

为了解决我的疑问,我通过如下函数foo1和foo2进行分析:

///片段1

var foo1 = function () {};

console.log(foo1);

//片段2

(function foo2(){})

console.log(foo2);
//代码效果参考:http://www.zidongmutanji.com/zsjx/524647.html

片段1

是让一个匿名函数表达式赋值给变量foo1,然后该函数可以用foo1这个名称进行访问——foo1()。所以打印是一个函数。

片段2

是一个函数表达式,但结果是Uncaught ReferenceError: foo2 is not defined。说明在外部是不可访问的。

可见,立即执行具名函数b是一个函数表达式,在外部是不可访问的!(ps:意味着函数表达式既不可能通过名称在函数声明之前调用它,也不可能在声明之后调用它)。

其实,大多数书籍里介绍以及我之前所理解的片段1这样的代码就是一个函数表达式。但现在我的理解并不是这样的~

foo1是一个变量,匿名函数表达式赋值给变量foo1了,所以foo1它可被访问!

通过自己写了2个代码片段,将我的疑惑迎刃而解了~

思考其他案例

在闲暇之余,我将最原始的代码块再做了改造,运用这些代码来温故并且思考了之前学习的理论基础。

如下的代码片段,我将结果也一并和大家揭晓,但我也会和大家分享一下我的心得~

///片段1

var b = 10;

function b() {

console.log(12);

return 1;

}

console.log(b, b());

//10 TypeError: b is not a function

为什么会打印10呢,而不是函数b呢?

论据:函数声明优先于变量声明~

所以,相当于先利用function声明了函数b,再利用var重写了b。

//片段2

console.log(b, b()); //12 1

var b = 10;

function b() {

console.log(12);

return 1;

}

为什么会打印函数b的执行结果12和1呢,而不是全局变量b呢?

论据:函数声明优先于变量声明~并且在这个过程中存在变量提升。

片段3

var b = 10;

b = function() {

b = 20;

console.log(b); //20

return 1;

};

console.log(b, b()); //b函数,1

为什么会打印10呢,而不是函数b呢?

论据:这个过程就是将变量b进行重新赋值。

所以,打印的是10,而不是函数。

片段4

var b = 10;

// Duplicate declaration "b"

let b = function() {

b = 20;

console.log(b);

return 1;

};

论据:用var声明变量可以可重复声明,但是用let声明变量不可重复声明。

所以js引擎要执行完var b = 10语句之后,遇到了let b之前报错了。

总结

在写业务代码的时候,要尽量去避免声明变量命名冲突的情况,因为以上案例的的写法是不合理的,很容易出现意想不到的结果。

为何不规范要求自己而避开不必要的麻烦呢?

当然,我觉得在学习乏味难啃的理论基础知识时,我觉得应该创造自己的想象力,多去实践多去思考为什么会有这样的结果呢?

根据理论证实结果!

相关文章
|
9天前
|
JavaScript 前端开发 Python
用python执行js代码:PyExecJS库
文章讲述了如何使用PyExecJS库在Python环境中执行JavaScript代码,并提供了安装指南和示例代码。
48 1
用python执行js代码:PyExecJS库
|
5天前
|
编解码 前端开发 JavaScript
javascript检测网页缩放演示代码
javascript检测网页缩放演示代码
|
7天前
|
Web App开发 JavaScript 前端开发
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
|
8天前
|
存储 JavaScript 前端开发
webSocket+Node+Js实现在线聊天(包含所有代码)
文章介绍了如何使用WebSocket、Node.js和JavaScript实现在线聊天功能,包括完整的前端和后端代码示例。
35 0
|
4天前
|
存储 JavaScript 前端开发
改进JavaScript代码,给水果有序赋色
改进JavaScript代码,给水果有序赋色
|
6天前
|
存储 JSON JavaScript
JavaScript帮我编写快递自动分拣的代码,区分省份市区县城乡镇
JavaScript帮我编写快递自动分拣的代码,区分省份市区县城乡镇在JavaScript中编写一个用于快递自动分拣的代码,区分省份、市区、县、城乡镇,通常意味着你需要一个数据结构来存储这些地理区域的信息,并编写逻辑来根据快递地址中的信息将其分配到正确的分类中。 这里,我将提供一个简化的示例,说明如何使用JavaScript对象和函数来实现这一功能。请注意,这个示例是高度简化的,并且假设你已经有了某种方式(如正则表达式或API调用)来从快递地址中提取省份、市区、县等信息。 ----------------------------------- ©著作权归作者所有:来自51CTO博客作者goS
|
7天前
|
JavaScript 前端开发 Python
python执行js代码
本文档详细介绍如何安装Node.js环境及PyExecJS库,并提供示例代码展示其功能。首先,通过指定链接安装Node.js,安装完毕后可在命令行中输入`node --version`来验证安装是否成功。接着,使用`pip install PyExecJS`安装PyExecJS库,该库允许Python程序执行JavaScript代码。文档还提供了多个示例代码,展示了如何在Python环境中执行和编译JavaScript代码,并可以选择特定的JavaScript运行时环境,如Node.js或JScript。最后,通过具体案例展示了PyExecJS的功能与使用方法。
14 3
|
16天前
|
JavaScript
网站内容禁止复制的js代码
网站内容禁止复制的js代码
|
22天前
|
缓存 JavaScript 前端开发
js和html代码一定要分离吗
JavaScript(JS)和HTML代码的分离虽非绝对必要,但通常被推荐
|
25天前
|
移动开发 JavaScript 安全
总有一款适合您分享78个JS相册代码
本文分享了78款JS相册代码,包括3D相册旋转木马、图片悬浮效果、倾斜图片幻灯片切换等特效,适用于各种图片展示场景。无论您需要哪种样式,都能在这里找到满意的解决方案。快来挑选吧!参考链接:[点击这里](https://www.vipwb.com/sitemap.xml)。
29 4
下一篇
无影云桌面