js变量的声明提升和函数的声明提升

Js代码分为两个阶段:编译阶段和执行阶段

Js代码的编译阶段会找到所有的声明,并用合适的作用域将它们关联起来。

包括变量声明(var a)和函数声明(function a(){})在内的所有声明都会在代码被执行前的编译阶段首先被处理。这个过程就好像变量声明和函数声明从他们代码中出现的位置被添加到最近执行环境的顶部,这个过程就叫做提升(hoisting)。

只有声明操作会被提升,赋值和逻辑操作会被留在原地等待执行。

变量的声明

js中,在使用一个变量之前应当先声明。变量是使用关键字var声明的,如:

var i;

var sum;

注:此时console.log(i)=undefined,因为此时的变量没有被赋值,默认初始值是undefined。

也可以使用一个var关键字声明多个变量:

var i,sum;

而且还可以将变量的初始赋值和变量声明合写在一起:

var m="hello";

var i = 0,j = 0,k = 0;

到这里你大概会发现js的变量声明中没有指定数据类型,就比如在C语言中,我们定义一个变量常常是int a;char c;。。。。这里的int char 就是所谓的数据类型

小知识:编程语言分为动态(类型)语言和静态(类型)语言,动态类型语言是指在运行期间才会去做数据类型检查的语言,也就是说,在用动态类型的语言编程的时,永远也不用给任何变量指定数据类型,该语言会在第一次赋值给变量时,在内部将数据类型记录下来。静态类型语言与动态类型语言刚好相反,它的数据类型是在编译期间检查的,也就是说在写程序时要声明所有变量的数据类型。

静态类型语言:C/C++、C#、JAVA等

动态类型语言:Python、Ruby、JavaScript等

变量声明提升

举个例子:

var a = 1;

var b =2;

上述两行代码在编译时,实际上它的顺序是这样的:

var a;    //undefined

var b;    //undefined

a = 1;    //1

b = 2;    //2

解释:编译器将var a = 1;这行代码分成两步操作,

第一步是变量的声明提升:var a;声明操作会在编译阶段进行,所有声明会被提升到最近执行环境的顶部,此时的变量值是初始值undefined。

第二步是常规的赋值操作:a = 0;

这里有一点要注意,JavaScript中声明变量可以不写前面的var关键字,这种是合法且可行的,去掉var时,会被默认成全局变量,但是我们不建议这样使用,这个不好的习惯会造成很多bug。严格模式下,不声明就使用一个变量也会导致错误。比如:

function add(num1,num2){

var sum = num1 + num2;

return sum;

}

var result = add(10,20);      //30

alert(sum);                        //由于sum在函数体内被声明过,在全局不是有效的变量,因此会导致错误

改成:

function add(num1,num2){

sum = num1 + num2;

return sum;

}

var result = add(10,20);      //30

alert(sum);           //30 此时的sum是全局变量,所以这里可以访问的到。但是不推荐

函数的声明

定义函数有三种方式:函数声明、函数表达式、Function构造函数(不推荐)

函数声明提升会在编译阶段把声明和函数体整体都提前到执行环境顶部,所以我们可以在函数声明之前调用这个函数。比如:

function sum(num1,num2){

return num1 + num2;

}

函数表达式,其实就是变量声明的一种,声明操作会被提升到执行环境顶部,并赋值undefined。赋值操作被留在原地等到执行。这种定义方式得到的函数也叫匿名函数(拉姆达函数),因为function关键字后面没有函数名字,只是把这个函数体赋值给一个变量。这种方式定义函数也没有必要使用函数名---通过变量名就可以引用函数。另外还要注意,此时函数末尾有一个分号,就像声明其他变量一样需要一个分号作为结尾。比如:

var sum = function (num1,num2){

return num1 + num2;

};

Function构造函数可以接收任意数量的参数,但最后一个参数始终都被看成函数体,而前面的参数枚举出了新函数的参数。比如:

var sum = new Function("num1","num2","return num1 + num2");        //不推荐

从技术上讲,这是一个函数表达式,但是这种语法会导致解析两次代码(第一次是解析常规的ES代码,第二次是解析传入构造函数中的字符串),从而影响性能。不过,这种语法对于理解“函数是对象,函数名是指针”的概念倒是非常直观的。

函数的声明提升

小知识:在一些类似C语言的编程语言中,花括号内的每一段代码都是具有各组的作用域,而且变量在声明它们的代码段之外是不可见的。我们称之为块级作用域(block scope),然而,JavaScript是没有块级作用域。JavaScript取而代之地使用了函数作用域(function scope):变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

function test(0){

var i = 0;        //i在整个函数体内均有定义

    if(typeof 0 == "object"){

    var j = 0;  //j在整个函数体内均有定义,不仅仅是在这个代码段内

for(var k = 0;k < 10;k++){  //j在整个函数体内均有定义,不仅仅是在这个循环内

        console.log(k);          //输出数字0--9

    }

      console.log(k);                  //k已经定义了,输出10

          }

    console.log(j);                        //j已经定义了,但可能没有初始化

}

JavaScript的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的,所以当在函数体内使用各种for嵌套循环时应定义不同的变量i,j,k等。

举个例子:

var scope = "global";

function f(){

console.log(scope);              //undefined

var scope = "local";              //变量在这里赋值,但是在整个函数体内都是有定义的

console.log(scope);              //local

}         

你可能会认为第一个console会输出“global”,但是由于函数作用域的特性,局部变量在整个函数体内都是有定义的,上述代码等价于:

var scope = "global";

function f(){

var scope;         //undefined,因为函数声明优先级更高,所以覆盖了第一行的赋值

console.log(scope);                //变量存在,但其值是初始值undefined

scope = "local";                  //变量在这里赋值为local

console.log(scope);                //local

}

最后总结,声明的顺序是这样的:

第一步. 找到所有的函数声明,初始化函数体,如有同名的函数则会进行覆盖

第二步. 查找变量声明,初始化为undefined,如果已经存在同名的变量,就什么也不做直接略过。

要注意咯,函数声明的优先级比变量声明的优先级高,如果是先声明并赋值了一个变量,后面的函数体内又声明了同名变量,此时的变量就被函数体内的变量覆盖了。

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