变量声明提升

变量声明提升是JS中一个基础的问题,同时也是对JS词法作用域认识的一个提升。在JS面试题中,关于变量声明提升的问题还是占了不少比例的,另外,在码代码的时候可能也无意间因为这个原因产生错误而头疼好久。还有一个需要注意的是ES2015中let、const声明的变量不具备变量声明提升。

在《你不知道的JavaSript》上卷中,作者把变量声明提升这个问题比作“先有鸡还是先有蛋?”,我认为很形象。代码在执行的时候给人的感觉是一行一行的执行,这样可能比较符合我们的正常思维习惯,但是这实际上并不完全正确。为什么这样说呢?这就要引出JS在运行前其实有一个编译过程的这个问题,在编译阶段,JS引擎做了一些事使得代码并不是完全一行一行的执行了,而是将一些声明的代码顺序提前了,所以就产生了变量声明提升这个问题。

编译原理

想明白变量声明提升这个概念,JS编译原理必须清楚。
有些小伙伴认为JS不是一门编译动态脚本语言吗?怎么会有编译过程,其实在没有接触《你不知道的JavaSript》上卷这本书之前我也这么认为,直到读了这本书我才对JS的作用域和变量声明提升以及闭包等问题有了更清楚的认识,所以这里先向小伙伴们推荐一下这本书。

言归正传,接着说JS编译,JS的编译过程不是像其他语言的编译过程一样发生在构建之前的,大部分是在代码执行之前的几微米(甚至更短!)的时间内,那么这段时间内,编译器对我们的代码做了什么呢?我们通过一个例子来说明一下,比如var a =2;这条语句在会被JS引擎看成是两部分,分别为var a;a = 2。其中前一部分是发生在编译过程中,而第二部分发生在执行过程中。也就是说,编译的时候,JS引擎把我们对a的声明已经提前了。

为了更好地说明编译器的编译过程,我在举一个例子:

foo(2);

function foo(a){
  console.log(a);
}

上面这段代码在执行的时候,JS引擎的工作过程是:

  1. 在编译阶段,首先遇到foo(2);一看这是个函数执行呀,这并不是我编译器的活呀,于是直接无视略过。
  2. 然后继续向下走,发现function,很明显是要声明一个函数(ES2015之前,声明变量只有var 和 function 这两个关键字,前者用于声明普通变量,后者用于声明函数或者方法),所以,JS引擎就会在当前作用域内的内存中开辟一块空间给foo;然后编译继续进行,这时候该对foo函数内部进行编译(从上到下一行一行编译),所以遇到形参a后,就在foo作用域的内存中为a开辟了一块空间,只不过此时a没有值,所以存的是undefined,继续向下走,没了-----结束。
  3. 现在开始执行阶段,首先遇到了foo(2);,开始干活:
    引擎:作用域,你见过foo没?
    作用域:见过,刚才编译器那小子刚声明了他,我给你。
    引擎:好的。那我来执行以下foo这个函数。
    引擎:作用域兄弟,你在foo中见过a吗?
    作用域:有,编译器也声明他了,给你。
    引擎:谢了哥们,我把2复制给他。

    .....

我发现虽然是简单描述了一下JS引擎的编译过程,好像已经莫名其妙的把变量声明提升给讲完了(尴尬。。。)。

变量声明提升

本文是用来记录变量声明提升的,结果在第一小节就通过JS引擎的编译过程就给讲完了。。。。。。

那这一小节就在再总结一下,顺便说一下函数优先吧!

变量声明提升的原因

  1. JS代码在执行之前有一个极其短的编译过程。
  2. 在这个过程中,JS引擎为var、function声明的变量和函数在当前作用域中分配内存空间。函数内的变量和嵌套函数也是一样,只不过分配的内存是其父函数作用域内的。
  3. JS引擎在执行的时候,通过询问作用域来查找有无该变量或者函数,然后执行相关赋值或者函数执行等操作。

函数优先

相信已经说清楚变量声明提升的原因了,但是还要注意一点就是,在编译过程中,如果var和function声明的变量为同一个,则function声明的优先级高于var声明的。来看一个例子吧!

foo();

var foo;

function foo(){
  console.log(1);
}

foo = function(){
  console.log(2);
}

上面代码最终输出结果是1,你猜对了吗?上面的编译执行过程为:

  1. 编译阶段,从上往下编译,首先遇到foo();,直接无视略过。
  2. 遇到var foo;,在当前作用域内为foo分配内存空间,继续向下编译。
  3. 遇到function foo(){....},发现已经在当前作用域中声明了该变量,但是此时是function,优先级明显高于var,所以当前作用域中的foo变为function。
  4. 继续向下编译,发现foo=....很明显是个赋值操作吗,这是引擎的事,无视。
  5. 执行阶段,首先就遇到了foo();,于是询问当前作用域内有无foo的声明,发现有,还正好是个函数,那就别废话了,直接执行吧!于是控制台打印了1。
  6. 继续向下执行,略过var foo;function foo(){....},遇到一个复制操作,那就先在问问当前作用域有没有foo变量,有就赋值,没有就在全局中声明一个foo变量(非严格模式下);
  7. 好了,到此结束。

小结

变量声明是一个很基础的JS知识点,但如果没有编译这一步,可能理解上不好理解,但是有了编译这个过程后,相信就很容易了。最后留下一道题,检验一下自己:

var a = new Object();
a.param = 123;

function foo(){
  get = function(){
      console.log(1);
  };
  return this;
}

foo.get = function(){
  console.log(2);
};

foo.prototype.get = function(){
  console.log(3);
};

var get = function(){
  console.log(4);
};

function get(){
  console.log(5);
}

foo.get();
get();
foo().get();
get();
new foo.get();
new foo().get();
new new foo().get();

很经典的一道考察变量声明提升和原型链,还有操作符优先级的题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容