资讯专栏INFORMATION COLUMN

通过这一段代码,让我们重新认识JavaScript

FrozenMap / 3025人阅读

摘要:问题请说明一下对这一段的理解,主要包括引擎编译执行作用域异常这些要点。这个过程叫提升。两个非常常见的异常是在什么情况下发生的。

问题

请说明一下对这一段JavaScript的理解,主要包括引擎、编译、执行、作用域、异常这些要点。然后猜测下会输出那些内容。

var hello = null;
var b = 2;
foo(3);
console.log(c);

function foo(a){
 try{
    console.log(c);
 }catch(error){
    console.log(error);
 }
 try{
    hello();
 }catch(error){
    console.log(error);
 }
 c = a*b;
 console.log(a+b);
}
理解 编译
/*
    1.编译器遇到 var hello这个声明语句,就在当前作用域中声明变量hello(当前作用域没有变量hello,这里当前作用域就是全局作用域)。
*/
var hello = null;
var b = 2;
foo(3);
console.log(c);
/*
    1.编译器在当前作用域把foo声明成一个函数,同上
    2.在函数的内部作用域声明a变量
*/
function foo(a){
 try{
    console.log(c);
 }catch(error){
    console.log(error);
 }
 try{
    hello();
 }catch(error){
    console.log(error);
 }
 c = a*b;
 console.log(a+b);
}

编译器会先找到所有的声明(var xxx,function xxx这些才是声明),然后在对应的作用域中创建该变量/函数,如果该声明不存在的话。这个过程叫‘提升’。

运行
/*
    1.运行时读取到的是hello = null,首先在作用域链中查找hello,找到的话执行赋值操作
*/
var hello = null;
var b = 2;
/*
    1.在作用域链中找foo并且执行它,这里隐式地执行了a = 3,这里的a实际上是foo函数作用域里声明的一个变量
    2.之后转入函数内部执行
*/
foo(3);
/*
    0.在函数执行完毕后,执行到这儿
    1.在作用域中查找console这一变量,然后找到了,然后获取它的log属性,然后把它作函数执行
    2.隐式地执行了x = c,在当前作用域中查找c,能找得到吗?
*/
console.log(c);

function foo(a){
 try{
    //尝试在作用域链中找c,找到本函数作用域-->全局作用域都没找到,于是抛出异常ReferenceError,这个异常就是在作用域链中找不到某变量但又需要知道它的值出现的,我们需要输出c的值
    console.log(c);
 }catch(error){
    console.log(error);
 }
 try{
    //尝试在作用域链中找hello,在全局作用域找到了,把它当函数执行,但它不是函数,于是抛出异常TypeError,这个异常就是找到了,但是使用方法不对
    hello();
 }catch(error){
    console.log(error);
 }
   //先计算a*b,在作用域链中找a和找b的值,然后执行c=6,又开始找c,想要给c赋值,找到头也找不到,于是自动地在全局作用域下声明了一个c,然后执行c=6,注意这里我们不关心c的值
 c = a*b;
 console.log(a+b);
}

js的作用域是词法作用域,就是说变量处于哪个作用域是由代码怎么写决定的,在编译期间确定。
作用域链就像个大楼,查找变量的时候从当前楼层查到顶楼(全局)为止

通过这段代码可大致理解js引擎在编译阶段做了什么,在执行阶段又怎么做,作用域在这两个阶段中起到什么作用(中间者,管家)。两个非常常见的异常是在什么情况下发生的。
・゜゚・:.。..。.:・"(゚▽゚)"・:.。. .。.:・゜゚・

参考书籍《你不知道的JavaScript(上卷)》第一部分,亚马逊电子书9.9元,强力推荐

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79306.html

相关文章

  • 悄悄掀起 WebAssembly 的神秘面纱

    摘要:在拿到这块内存后,是拥有完全操作的权利的。后面定义了一个函数,并导出为函数。首先,使用在栈内压入一个位整型常数,然后使用在栈内压入一个位整型常数,之后调用指令,这个指 前端开发人员想必对现代浏览器都已经非常熟悉了吧?HTML5,CSS4,JavaScript ES6,这些已经在现代浏览器中慢慢普及的技术为前端开发带来了极大的便利。得益于 JIT(Just-in-time)技术,Java...

    qc1iu 评论0 收藏0
  • 重新认识定时器

    摘要:重新认识三如果被推迟执行的回调函数是某个对象的方法,那么该方法中的关键字将指向全局环境,而不是定义时所在的那个对象。 重新认识一 一般,setTimeout函数接受两个参数,第一个参数func|code是将要推迟执行的函数名或者一段代码(引擎内部使用eval函数,将字符串转为代码),第二个参数delay是推迟执行的毫秒数。但是,setTimeout 还可以添加更多参数。第二个之后的参数...

    paney129 评论0 收藏0
  • JavaScript的计时器的工作原理

    摘要:创建了一个简单的计时器,在经过给定的时间后,回调函数将会被执行。接受一个计时器由之前两种计时器返回并且停止计时器回调函数的执行。然而,我们可以注意到,当定时器再一次触发在计时器回调函数正在执行的时候,这一次定时器回调函数被丢弃了。 最近都在看一些JavaScript原理层面的文章,恰巧看到了jQuery的作者的一篇关于JavaScript计时器原理的解析,于是诚惶诚恐地决定把原文翻译成...

    geekzhou 评论0 收藏0
  • 通过分析这段代码的进化历程,或许能够加深您对JavaScript的作用域的理解

    摘要:前言这里我们不讨论作用域链的问题,这些问题您可以看下我之前写的东西,通过这一段代码,让我们重新认识。这回我们主要来分享一下,中作用域的创建方式。立即执行函数是个不错的选择,但具名的立即执行函数可以让代码本身更具有可读性,是个最佳实践。 前言 这里我们不讨论作用域链的问题,这些问题您可以看下我之前写的东西,通过这一段代码,让我们重新认识JavaScript。这回我们主要来分享一下,Jav...

    goji 评论0 收藏0
  • Web技术的前世今生(二)

    摘要:前言我是,如果你还不认识我,不妨先看看技术的前世今生一平静的生活已经有一段日子了。传送门技术的前世今生一技术的前世今生三 前言:我是JavaScript,如果你还不认识我,不妨先看看《Web技术的前世今生(一)》 平静的生活已经有一段日子了。 这一天,HTML大哥面露不悦地走过来问我: Js,你是打算和我们分家吗? 大哥,您这说的哪里话,我什么地方做的不对么?我一脸茫然地回答道。 哼,...

    Stardustsky 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<