JS当中的变量提升(预解析)

函数和变量声明的提升

在JS中存在一个很重要的特性,函数和变量声明的提升,理解这一点对于理解我们编写的代码非常有帮助,那么什么是声明的提升呢?我们通过下面的代码来分析。

console.log(a);//①
var a = 123;
console.log(a);//②

console.log(f);//③
f();//④
function f() {
    console.log("函数声明提升");
}

①处的代码如果按照我们以前的理解,代码从上而下执行,那么在执行这行代码的时候,a还没有被声明,所以直接访问一个没有被声明的变量,程序应该报错。

但是结果却大出所料,这里得到的结果是undefined。

③处的结果也和我们最初的认识是不一样的,结果为f对应的函数对象。

造成这个结果是因为变量和函数的作用域提升的原因,什么意思呢?

JS是解释性语言,JS引擎对代码的处理分为两步:

​ 预解析处理:在代码执行之前,对代码做全局扫描,对代码中出现的变量或者函数提前声明处理;

​ 解析之后我们的代码:

var a;//提前声明,但不初始化
console.log(a);//undefined
a = 123;
console.log(a);//123

//提前声明
function f() {
    console.log("函数声明提升");
}
console.log(f);//函数对象
f();//函数声明提升

​ 调用执行:自上而下的执行代码

变量提升和作用域的关系

题1:

f();
function f() {
    console.log("1");
}
f();
function f() {
    console.log("2");
}
f();
function f() {
    console.log("3");
}

根据前面对函数声明提升的认识,结果三次都是 “3”。

预解析之后的代码:

function f() {
        console.log("3");
}
f();
f();
f();

为什么解析之后只剩下一个函数,而且是最后那一个?

因为三个函数的名称一样,后面的函数会将前面的覆盖,所以最后只剩下最后一个函数了。

题2:

console.log(a);
var a = 123;
console.log(a);
function f1() {
    console.log(a);
    var a = 456;
    console.log(a);
}
f1();
console.log(a);

直接先对代码做预解析,然后再做分析。

var a;//变量声明提升
function f1() {//函数声明提升
    var a;//变量声明提升
    console.log(a);
    a = 456;
    console.log(a);
}
console.log(a);
a = 123;
console.log(a);
f1();
console.log(a);

解析得到上面的代码结果就非常明显了,分别是:undefined 123 undefined 456 123

由于在函数内部有变量a,所以在函数中访问到的是这个局部变量,如果在函数作用域中没有变量a,那么就会跳出函数作用域来到全局作用域来查找。

声明提升的规则

声明提升是将变量或者函数的声明提升到当前作用域的最顶端。在具体使用的过程中存在以下需要注意的细节。

  1. 变量和变量同名,解析之后只存在一个当前变量的声明
console.log(a);
var a = 123;
console.log(a);
var a = 456;
console.log(a);

解析之后:

var a;
console.log(a);//undefined
a = 123;
console.log(a);//123
a = 456;
console.log(a);//456
  1. 函数和函数同名,后面的声明将前面的覆盖
f();
function f() {
    console.log("1");
}
f();
function f() {
    console.log("2");
}
f();
function f() {
    console.log("3");
}

解析之后:

function f() {
    console.log("3");
}
f();//3
f();//3
f();//3
  1. 函数和变量同名,函数声明提升,忽略变量的声明
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
function a() {}
console.log(a);

解析之后:

function a() {}
console.log(a);//函数a
var a = 123;//将前面的函数覆盖,a的值变为123
console.log(a);//123
console.log(a);//123
console.log(a);//123
  1. 如果是命名函数,则只将前面的变量声明提升,函数不动。
console.log(fn1);
function fn1() {
}
console.log(fn1);
console.log(fn2);
var fn2 = function () {
}
console.log(fn2);

解析之后:

function fn1() {
}
var fn2;
console.log(fn1);//fn1函数
console.log(fn2);//undefined
fn2 = function () {
}
console.log(fn2);//fn2函数

面试题1:

console.log(a,b); //undefined undefined
var a=12;
var b=13;

sum(); //1
function sum(){
    console.log(1);
}

面试题2:

console.log(a); //undefined
var a=12;
function fn(){
    console.log(a); //undefined
    var a=13;

}
fn();
console.log(a); //12

面试题3:

console.log(a); //undefined
var a=12;
function fn(){
    console.log(a);//12
    a=13;
}
fn();
console.log(a)//13

面试题4:

console.log(a);//这个就直接报错了,因为没有变量提升 a is not defined
a=12;
function fn(){
    console.log(a);
    var a = 13;
}
fn();
console.log(a)

面试题5:

var foo=1;
   function bar(){
       //不管条件是否成立,都要进行变量提升
       //这时的foo属于私有变量 给的默认值是undefined,undefined取反就为真
       if(!foo){
           var foo=10;
       }
       console.log(foo);
   }
   bar();//10

面试题6:

var n=13;
function fn(n) {
    alert(n); // 13
    var n=14;//有形参赋值了,就不在走变量提升了
    alert(n); // 14
}
fn(n);
console.log(n);//13

面试题7:

console.log(a);// undefined
a=12;
function fn(a) {
    console.log(a); //undefined
    a=13;
}
fn();//注意这里没有传值
var a;
console.log(a); //12

面试题8:

function f1() {
    if("a" in window){//带var的变量提升时不看条件成立不成立的都会提升。
        var a = 10; //函数体中声明的变量是局部变量 所以不在window
    }
    console.log(a);//undefined
}
f1();

面试题9:

if(!"a" in window){//使用var声明的全局变量会变成window成员。
    var a = 10;
}
console.log(a);//undefined

面试题10:

console.log(a, b, c);// undefined undefined undefined
var a=10,b=20,c=30;
function f(a) {
    console.log(a, b, c);// 10 undefined 30
    var b=a=c=100;      //a 和 b 是局部变量,只有c是全局变量
    console.log(a, b, c);//100 100 100
}
f(10,20);
console.log(a, b, c);// 10,20,100     

面试题11:

function foo() {
        var num = 123;
        console.log(num);//123
    }
    foo();
    console.log(num);//报错  num is not defined

面试题12:

var scope = "global";
foo();
function foo() {
    console.log(scope);//undefined
    var scope = "local";
    console.log(scope);//local
}

面试题13:

var foo = 1;
function bar() {
   if(!foo){     //foo变量提升完是undefined  取反条件成立
       var foo = 10;  
   }
    console.log(foo);//10
}
bar();
 console.log(foo);//1

面试题14:

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