重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要讲解了“如何论证JS基础”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何论证JS基础”吧!
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名与空间、网页空间、营销软件、网站建设、陆河网站维护、网站推广。
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);
片段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之前报错了。
感谢各位的阅读,以上就是“如何论证JS基础”的内容了,经过本文的学习后,相信大家对如何论证JS基础这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!