JavaScript作用域和变量提升

一、JS的作用域

1.JS采用词法作用域

首先,我们得知道JavaScript采取的是词法作用域,而不是动态作用域。
那么什么是词法作用域,什么是动态作用域呢?

引用一下我以前在知乎上看到的一句精简的描述:

词法作用域的函数中遇到既不是形参也不是函数内部定义的局部变量的变量时,去函数定义时的环境中查找。

动态作用域的函数中遇到既不是形参也不是函数内部定义的局部变量的变量时,去函数调用时的环境中找。

如果对这句话还是不太明白的朋友,可以观察以下代码:

var a = "这是第一个a";
function func01() {
    console.log(a);         //先在当前作用域中查找,如果没有则访问全局的作用域
}

function func02() {
    var a = "这是第二个a";
    func01()
}

func01();       //打印结果为:这是第一个a
func02();       //打印结果为:这是第一个a(倘若JS用的是动态作用域,这里将输出第二个a)

2.JS没有块作用域(try,catch为特例)

在大多数语言中,都是有块作用域的,比如C、C++、C#、Java、Object-C等等,而JS没有块作用域。

下面分别是C和OC的代码

#include <stdio.h>
int main() {
    int a = 1;
    if (1) {
        int a = 2;
        printf("%d, ", a); // 2
    }
    printf("%d\n", a); // 1
}
NSString *str = @"码农1号";  
if (true) {
    NSString *str = @"码农2号";
    NSLog(@"%@", str);  //码农2号
}
NSLog(@"%@", str);  //码农1号

在C和OC中,if花括号内定义的变量,在if语句执行完后,就被销毁了。那么我们再来看看类似的代码运行在JS中。

var a = "global";
if (true) {
    var a = "if";
    console.log(a);  //if
}
console.log(a);  //输出为:if  证明if语句内定义的变量,是全局变量  

那么在JS中,我们能否像其它语言一样创建出类似块作用域的效果呢?答案是可以的,利用闭包!

因为在JS在只存在全局作用域函数作用域,因此我们可以巧妙的利用一下函数作用域创建出块作用域的效果,我们把上面的JS代码改造一下:

var a = "global";
if (true) {
    (function() {
        var a = "if";
        console.log(a);  //if
    })();
}
console.log(a);  //global  

上面代码在if内创建了一个闭包,它是一个立即调用的匿名函数,因此这里创建出了一个函数作用域,在此函数作用域里定义的变量,将不影响全局变量,并且函数执行完后,该变量会被销毁。
这样利用闭包的好处是:限定作用域,不怕污染全局变量。

二、JS中的变量提升和函数提升

1.变量的提升

在JS代码编译时,函数声明和变量定义会被解释器移动到其所在作用域的最顶部!

怎么理解这句话呢?我们来看下面代码

console.log(a); //报错
console.log(a);  //undefined
var a = 10;

为什么上面代码不报错?因为上面代码在编译器解析完后,变成了下面的形式:

var a;
console.log(a);
a = 10;

那么我们再看下面的例子,猜猜它们的输出结果

var a = "global";
fun();
function fun() {
  console.log(a); //1.?
  var a = "local";
}
console.log(a); //2.?

输出结果是 1. undefined, 2. global

上面的代码的正确解析如下:

var a;
function fun() {     
  var a;    //此变量所处域为函数域,因此其作用域最顶部是这里
  console.log(a); //undefined
  a = "local";
}
a = "global"
fun();
console.log(a);   //global   (函数域创建的变量不污染到外面)

2.函数表达式的提升(非函数声明)

先看例子:

console.log(fun);  //undefined
var fun = function () {
  console.log("我是一个函数");
}

上面的函数提升跟变量的提升一样,解析完如下:

var fun;
console.log(fun);  //undefined
fun = function () {
  console.log("我是一个函数");
}

3.函数声明的提升

先看例子:

console.log(fun);  //整个函数打印出来
function fun() {
  console.log("我是一个函数");
}

解析完如下:

function fun() {
  console.log("我是一个函数");
}
console.log(fun);  //整个函数打印出来

由此我们可以得出结论:JavaScript编译时,对于函数表达式的提升是跟普通变量提升一样的,仅提升声明但不赋值。对于函数声明的提升,则是整个提升,我们可以理解为声明+赋值的提升。

总结:

  1. 只有函数可以限定作用域

  2. 在函数内部允许访问外部的变量,但外部不能访问函数内部变量

  3. 如果当前作用域中有该变量,则不考虑外部作用域的同名变量

  4. 对于变量和函数表达式的提升,仅提升声明,不赋值

  5. 对于函数声明的提升,是声明+赋值

本农搞了个小练习给大家练练手,如果做对基本对于该文你也就懂了,先不要看最下面的解析结果

var a = "global";
function fun() {
    a = "local";
    return;
    function a() {}
}
fun();
alert(a);

解析结果为:

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

推荐阅读更多精彩内容