JavaScript基础06- 作用域与预解析

作用域

通俗来讲,作用域是一个变量或函数的作用范围。作用域在函数定义时,就已经确定了。目的是为了提高程序的可靠性,减少命名冲突。

作用域的分类

  1. 全局作用域
  2. 局部作用域(函数作用域)

根据作用域的不同,变量可以分为两类: 全局变量和局部变量

全局变量

  1. 在全局作用域下声明的变量,叫「全局变量」。在全局作用域的任何一地方,都可以访问这个变量。
  2. 在全局作用域下,使用 var 声明的变量是全局变量。
  3. 在函数内不使用 var 声明的变量也是全局变量(不建议这么用)。

局部变量

  1. 定义在函数作用域的变量,叫「局部变量」。
  2. 在函数内部,使用 var 声明的变量是局部变量。
  3. 函数的形参也是属于局部变量。
    从执行效率来看全局变量和局部变量:
  4. 全局变量:只有浏览器关闭时才会被销毁,比较占内存。
  5. 局部变量:当其所在的代码块运行结束后,就会被销毁,比较节约内存空间。

作用域链

只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。

  1. 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(就近原则)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错。
  2. 在函数中要访问全局变量可以使用window对象。(比如说,全局作用域和函数作用域都定义了变量a,如果想访问全局变量,可以使用window.a)
  3. 全局作用域在页面打开时创建,在页面关闭时销毁。
  4. 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,由浏览器创建,我们可以直接使用。全局作用域创建的变量都会作为window对象的属性保存。比如在全局作用域内写 var a = 100,这里的 a 等价于 window.a。创建的函数都会作为window对象的方法保存。

预解析

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程

预解析过程

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 先提升var,在提升function

变量的声明提前

使用var关键字声明的变量( 比如 var a = 1),会在所有的代码执行之前被声明(但是不会赋值),但是如果声明变量时不是用var关键字(比如直接写a = 1),则变量不会被声明提前。
所以,既然JS中存在变量提升的现象,那么,在实战开发中,为了避免出错,建议先声明一个变量,然后再使用这个变量。

函数的声明提前

使用函数声明的形式创建的函数function foo(){},会被声明提前。也就是说,整个函数会在所有的代码执行之前就被创建完成。所以,在代码顺序里,我们可以先调用函数,再定义函数。

 fn1();  // 虽然 函数 fn1 的定义是在后面,但是因为被提前声明了, 所以此处可以调用函数
    function fn1() {
        console.log('上边儿调用的时候,函数声明已经被提前了');
    }

使用函数表达式创建的函数var foo = function(){},不会被声明提前,所以不能在声明前调用。

函数表达式

函数作用域

  1. 函数中,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明。
  2. 函数中,没有var声明的变量都是全局变量,而且并不会提前声明。

注意,定义形参就相当于在函数作用域中声明了变量。

 function fun(e) { // 这个函数中,因为有了形参 e,此时就相当于在函数内部的第一行代码里,写了 var e;
        console.log(e);
    }

函数预编译步骤

预编译四部曲:

  1. 函数在运行的瞬间,生成一个执行期上下文 (Active Object),简称AO;
  2. 分析参数
    2.1 函数接收形式参数,添加到AO的属性,并且这个时候值为undefine,例如AO.age=undefined;
    2.2 接收实参,添加到AO的属性,覆盖之前的undefined;
  3. 分析变量声明,如var age;或var age=23;
    3.1 如果上一步分析参数中AO还没有age属性,则添加AO属性为undefined,即AO.age=undefined;
    3.2 如果AO上面已经有age属性了,则不作任何修改;
  4. 分析函数的声明,如果有function age(){};把函数赋给AO.age ,覆盖上一步分析的值;
函数预编译

执行期上下文:
当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁

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