精华内容
下载资源
问答
  • 第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升。这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下。 今天主要介绍以下几点: 1. 变量提升 2. 函数提升 3....
  • 1在js中只有两种作用域 a:全局作用域 b:函数作用域 在ES6之前,js是没有块级作用域。 首先来解释一下什么是没有块级作用域?...3:什么是函数提升? 输出的结果是: 注意:函数声明式,会将函数的声明和定
  • JavaScript中的变量提升和函数提升

    千次阅读 多人点赞 2018-03-29 14:31:26
      在理解变量提升和函数提升之前,我们需要先理解好JavaScript的作用域的奇特之处。 没有块级作用域   和C、C++、以及Java不同,在ES6之前,JavaScript没有块级作用域,只有全局作用域和函数作用域。 注...

    文章是本人大三期间的学习笔记,一些论断取自书籍和网上博客,碍于当时的技术水平有一些写得不够好的地方,可以在评论处理智讨论~

    变量的作用域


    在理解变量提升和函数提升之前,我们需要先理解好JavaScript的作用域的奇特之处。

    没有块级作用域

    和C、C++、以及Java不同,在ES6之前,JavaScript没有块级作用域,只有全局作用域函数作用域

    **注:**其实从 ES3 发布以来,JavaScript 就有了块级作用域(withcatch分句),而 ES6 引入了 let

    我们首先来看下面这个例子:

    ps:下面代码可以直接复制出去运行哦

    <script type="text/javascript">
    function test() {
    	if(1) {
    		var j = 0;//j存在于test()中任何地方,不止在if{}中
    		for(var k = 0; k < 10; k++) {}
    		console.log("k = " + k);//k存在于test()中任何地方,不止在循环中
    	}
    	console.log("j = " + j);
    }
    test();
    </script>
    

    对于初学JavaScirpt,写惯了C、C++、Java的童鞋来说,这已经是一个很奇特的结果了。

    此外,在函数作用域中,局部变量的优先级比同名的全局变量高。如果给一个局部变量或函数的参数声明的名字与某个全局变量的名字相同,那么就会有效地隐藏这个全局变量了。

    变量提升


    在了解了关于作用域的前置知识后,我们来聊聊提升这个有趣的现象。

    首先举个栗子~

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

    上面会输出什么呢?

    是由于变量 a 在使用前没有先进行声明,因此会抛出 ReferenceError异常?还是输出 2 ?

    不过上面的两种猜测都不对,正确答案是输出 undefined(已声明未定义值)

    这就是一个典型的 变量提升 现象。

    当你看到 var a = 2;时,可能会认为这只是一个简单的声明语句。但 JavaScript 实际上会将其看成两个声明: var a;a = 2;。第一个定义声明是在编译阶段进行的,第二个赋值声明会被留在原地等待执行阶段

    因此上面的代码会以如下的形式进行处理:

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

    因此,打个比方,这个过程就好像变量和函数声明从它们在代码中出现的位置被“移动”到了最上面。这个过程就叫做 提升

    注:无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理。可以将这个过程形象地想象成所有的声明(变量和函数)都会被“移动”到各自作用域的最前端,这个过程被称为 变量(函数)提升

    函数提升


    接着让我们来结合函数以及作用域以及上面的变量提升来看一个有趣的题目(这极有可能会出现在面试题中):

    var a = true;
    foo();
    
    function foo() {
    	if(a) {
    		var a = 10;
    	}
    	console.log(a);
    }
    

    这个例子最终的答案是 undefined。这是个很有趣的题目包含了许多可能会在 JavaScript 中碰到的坑。

    下面是这段代码实际会被 JavaScript 执行的样子:

    function foo() {
    	var a;
    	if(a) {
    		a = 10;
    	}
    	console.log(a);
    }
    var a;
    
    a = true;
    
    foo();
    

    var a = true;被解析成上面第1、2行不足为奇。

    首先,我们来看 foo(...) {} 的位置被移到了 foo();的前面,根据前面对变量提升的解释,我们可以很容易理解这是函数发生了提升,这就是函数提升

    继续我们来分析 foo(...) {} 中的代码。为什么会输出 undefined,而不是我们期望的 10,玄机都在其中!

    让我们回到最前面对作用域的理解,在 JavaScript 中没有块级作用域,所以 var a = 10;会被 JavaScript 分为两步中的 var a; 会被提升到函数作用域中的最顶端,声明了一个局部变量 a,在 foo(...) {} 的函数作用域中,这个重名局部变量 a 会屏蔽全局变量 a,换句话说,在遇到对 a 的赋值声明之前,在 foo(...) {},a 的值都是 undefined
      所以一个 undefined 的 a 进入不了 if(a) {...} 中,所以最后被打印出来的是 undefined

    需要注意的一点是,在 JavaScript 中,函数有两种方式进行声明,函数声明会被提升,但是函数表达式却不会被提升

    将上面的例子进行修改:

    var a = true;
    foo();
    
    var foo = function() {
    	if(a) {
    		var a = 10;
    	}
    	console.log(a);
    }
    

    这里会抛出 TypeError,而不是 ReferenceError

    常量提升,代码会被解析为:

    var a;
    var foo;
    
    a = true;
    foo();
    
    foo = function() {
    	if(a) {
    		var a = 10;
    	}
    	console.log(a);
    }
    

    在执行阶段时,当碰到 foo();时,foo 还没有赋值(如果它是一个函数声明而不是函数表达式,那么就会赋值)。foo(); 由于对 undefined 值进行函数调用而导致非法操作,因此会抛出 TypeError 异常。(关于TypeErrorReferenceError 的区别,可移步 TypeError 和 ReferenceError )。

    函数优先


    函数声明和变量声明都会被提升。但是有一个需要注意的细节是函数会首先被提升,然后才是变量

    考虑下面的代码:

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

    会输出 1 而不是 2!这个代码片段会被引擎理解为如下形式:

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

    然后,如果是两个函数声明,出现在后面的函数声明可以覆盖前面的

    foo();	//2
    function foo() {
    	console.log('1');
    }
    function foo() {
    	console.log('2');
    }
    

    上面的代码会被解析成:

    function foo() {
    	console.log('1');
    }
    function foo() {
    	console.log('2');
    }
    
    foo();	//2
    
    展开全文
  •   在JS执行前会对代码进行预处理,把当前作用域的变量和函数提升到顶部 (全局作用域、局部作用域)。变量只提升声明,赋值依旧在实际代码所在处;函数是声明和赋值都提升,且函数提升函数提升优先级高于变量提升。...

      在JS执行前会对代码进行预处理,把当前作用域的变量和函数提升到顶部 (全局作用域、局部作用域)。变量只提升声明,赋值依旧在实际代码所在处;函数是声明和赋值都提升,且函数提升,函数提升优先级高于变量提升

    变量提升

    var testVar = 1;
    console.log(testVar);    //1
    
    -------------解析完实际执行时
    var testVar;
    console.log(testVar);    // undefined
    testVar = 1;
    console.log(testVar);    // 1
    
    这里是把声明、赋值分开执行,以便在当前作用域调用。
    声明提升到当前作用域顶部,赋值仍在赋值代码所在处。
    
    
    ------------同名变量提升
    console.log(a)
    var a = 1
    console.log(a)
    var a = 2
    console.log(a)
    
    //-------------解析完顺序是这样的
    var a;
    var a; //忽略
    console.log(a) // undfined
    a = 1
    console.log(a) //1
    a = 2
    console.log(a)//2
    这是因为同名变量,声明会被提升,后边会忽略。
    

    函数提升

    函数提升,函数提升优先级高于变量提升
    
    console.log(bar);         // f bar() { console.log(123) }
    console.log(bar());       // undefined
    var bar = 456;
    function bar() {
        console.log(123);     // 123
    }
    console.log(bar);         // 456
    bar = 789;
    console.log(bar);         // 789
    console.log(bar())        // bar is not a function
    
    -----------------解析后
    函数提升,函数提升优先级高于变量提升
    var bar = function() {
        console.log(123)
    };
    // 变量提升,变量提升不会覆盖(同名)函数提升,只有变量再次赋值时,才会被覆盖
    var bar;
    console.log(bar);
    console.log(bar());
    
    bar = 456;               // 变量赋值,覆盖同名函数
    console.log(bar);
    
    bar = 789                // 再次赋值
    console.log(bar);
    console.log(bar());
    
    
    //---------同名函数
    function a(){console.log(1)}
    console.log(a)
    function a(){console.log(2)}
    console.log(a)
    a()
    
    //---------解析完
    function a(){console.log(1)}
    function a(){console.log(2)}
    console.log(a)
    console.log(a)
    a()
    
    
    // --------执行, 同名函数会被覆盖。
    function a(){console.log(2)}
    2
    
    
    
    // 匿名函数赋值给变量,是按照变量提升的方式,即:
    var testFun = function() {};
    
    解析时
    var testFun;
    testFun = function () {};
    
    展开全文
  • 本文实例讲述了JavaScript中变量提升与函数提升。分享给大家供大家参考,具体如下: 从两个实例说起: eg1: var i; console.log(i); // 2 eg2: console.log(i); // undefined var i = 2; 1、提升 变量和函数...
  • 变量提升和函数提升,以及它们的优先级

    千次阅读 多人点赞 2018-11-23 15:59:50
    ES6之前,函数没有块级作用域(一对{}即一个块级作用域),只有全局作用域和函数作用域。变量提升是指将变量申明提升到它所在的作用域的最开始部分。 例子: console.log(foo); // undefined var foo = '小花猫';...

    一、变量提升

    ES6之前,函数没有块级作用域(一对{}即一个块级作用域),只有全局作用域和函数作用域。变量提升是指将变量申明提升到它所在的作用域的最开始部分。

    例子:

    console.log(foo); // undefined
    var foo = '小花猫';
    console.log(foo)  // 小花猫

    相当于:

    var foo;
    console.log(foo);
    foo = '小花猫';
    console.log(foo);

    二、函数提升

    函数创建有两种方式:1、函数申明形式;2、函数字面量形式(即函数表达式)。【而只有函数声明形式才有函数提升】,还有一种是方式:函数构造法:var a = new Fun(),技术角度来讲也是一个字面量形式。

    // 声明式
    function foo () {
        // to do...
    }

    函数提升,相当于:

    // 函数字面量
    var foo = function () {
        // to do...
    }

    例子:

    console.log(bar);  // f bar() { console.log(123) }
    console.log(bar()); // undefined
    var bar = 456;
    function bar() {
        console.log(123); // 123
    }
    console.log(bar); // 456
    bar = 789;
    console.log(bar); // 789
    console.log(bar()) // bar is not a function

    相当于:

    // js执行步骤
    
    // 函数提升,函数提升优先级高于变量提升
    var bar = function() {
        console.log(123)
    };
    // 变量提升,变量提升不会覆盖(同名)函数提升,只有变量再次赋值时,才会被覆盖
    var bar;
    console.log(bar);
    console.log(bar());
    // 变量赋值,覆盖同名函数字面量
    bar = 456;
    console.log(bar);
    // 再次赋值
    bar = 789
    console.log(bar);
    console.log(bar());

    结果:

    // js执行结果
    
    f bar() { console.log(123) }
    123  // 执行bar()里的console.log
    undefined // bar()的返回值,如果函数没有返回值,默认为:undefined
    456
    789
    [typeError]:bar is not a function

    三、优先级

    函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖

     

    最后留个练习题,大家思考一下。

    console.log(person)
    console.log(fun)
    var person = 'jack'
    console.log(person)
    
    function fun () {
        console.log(person)
        var person = 'tom'
        console.log(person)
    }
    fun()
    console.log(person)

     

    展开全文
  • js中的变量提升和函数提升

    万次阅读 多人点赞 2018-10-30 13:30:09
    然后,Dmitry Soshnikov又提到了函数提升,他提到了相互递归(就是A函数内会调用到B函数,而B函数也会调用到A函数):  Brendan Eich又给出答案:  Brendan Eich很确定的说,函数提升就是为了解决相互递归的...
    console.log(a);
    var a = "a";
    var foo = () => {
        console.log(a);
        var a = "a1";
    }
    foo();

    由于js自上而下逐行解释执行的,有人可能会认为第一行代码引用了一个没有声明的变量a,会抛出 ReferenceError  异常,而注掉第一行后,由于变量 a 在第二行log之前已经声明并赋值,打印结果应该是 "a"。而实际的执行结果是:

    undefined
    undefined

    一、什么是提升(Hosting)?

    引擎会在解释JavaScript代码之前首先对齐进行编译,编译过程中的一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来,这也正是词法作用域的核心内容。

    简单说就是在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。举例来说:

    console.log(a);
    var a = 3;
    //预编译后的代码结构可以看做如下
    var a; // 将变量a的声明提升至最顶端,赋值逻辑不提升。
    console.log(a); // undefined
    a = 3; // 代码执行到原位置即执行原赋值逻辑

    二、变量提升

    变量声明的提升是以变量所处的第一层词法作用域为“单位”的,即全局作用域中声明的变量会提升至全局最顶层,函数内声明的变量只会提升至该函数作用域最顶层。那么开始的一段代码经过预编译则变为:

    var a;
    console.log(a); // undefined
    a = "a";
    var foo = () => {
        var a; // 全局变量会被局部作用域中的同名变量覆盖
        console.log(a); // undefined
        a = "a1";
    }
    foo();

    输出undefined就很明了。 

    ES6新增了let和const关键字,使得js也有了“块”级作用域,而且使用let和const 声明的变量和函数是不存在提升现象的,比较有利于我们养成良好的编程习惯。

    三、函数提升

    有了上面变量提升的说明,函数提升理解起来就比较容易了,但较之变量提升,函数的提升还是有区别的。举例说明:

    console.log(foo1); // [Function: foo1]
    foo1(); // foo1
    console.log(foo2); // undefined
    foo2(); // TypeError: foo2 is not a function
    function foo1 () {
    	console.log("foo1");
    };
    var foo2 = function () {
    	console.log("foo2");
    };
    

    即函数提升只会提升函数声明,而不会提升函数表达式。

    再举一个小例子:

    var a = 1;
    function foo() {
        a = 10;
        console.log(a);
        return;
        function a() {};
    }
    foo();
    console.log(a);

    直接上结果:

    10
    1

     上面的代码块经过预编译后可以看做如下形式(只分析foo方法内部情况):

    var a = 1; // 定义一个全局变量 a
    function foo() {
        // 首先提升函数声明function a () {}到函数作用域顶端, 然后function a () {}等同于 var a =  function() {};最终形式如下
        var a = function () {}; // 定义局部变量 a 并赋值。
        a = 10; // 修改局部变量 a 的值,并不会影响全局变量 a
        console.log(a); // 打印局部变量 a 的值:10
        return;
    }
    foo();
    console.log(a); // 打印全局变量 a 的值:1

     四、为什么会有提升?

    搬运:

    下面是Dmitry Soshnikov早些年的twitter,他也对这个问题十分感兴趣, Jeremy Ashkenas想让Brendan Eich聊聊这个话题::

     Brendan Eich给出了答案: 

    大致的意思就是:由于第一代JS虚拟机中的抽象纰漏导致的,编译器将变量放到了栈槽内并编入索引,然后在(当前作用域的)入口处将变量名绑定到了栈槽内的变量。(注:这里提到的抽象是计算机术语,是对内部发生的更加复杂的事情的一种简化。)

    然后,Dmitry Soshnikov又提到了函数提升,他提到了相互递归(就是A函数内会调用到B函数,而B函数也会调用到A函数):

     Brendan Eich又给出答案:

     Brendan Eich很确定的说,函数提升就是为了解决相互递归的问题,大体上可以解决像ML语言这样自下而上的顺序问题。

     最后,Brendan Eich还对变量提升和函数提升做了总结:

    大概是说,变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。

     

    后记:

      上面有个段落说到的es6之后使用let和const不存在提升是不准确的,可参考: 

       https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6

       大致意思是js中无论哪种形式声明(varletconstfunctionfunction*class)都会存在提升现象,不同的是,  var,function,function*的声明会在提升时进行初始化赋值为 undefined,因此访问这些变量的时候,不会报 ReferenceError 异常,而使用 let,const,class 声明的变量,被提升后不会被初始化,这些变量所处的状态被称为“temporal dead zone”,此时如果访问这些变量会抛出ReferenceError 异常,看上去就像没被提升一样。

     

     

     

     

    展开全文
  • 下面小编就为大家带来一篇基于js的变量提升和函数提升(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 变量提升与函数提升

    千次阅读 2019-06-08 09:11:48
    在使用var声明对象的时候就算声明在赋值之后依然可以使用,这就是函数提升: var a = "globalvale"; function fn (){ console.log(a); var a="functionvar"; } fn();//"undefine" 在上面的例子当中我们发现...
  • 什么是变量提升和函数提升

    千次阅读 2020-03-28 17:30:10
    猜猜输出什么? ...第一步骤是读取js代码,将所有变量声明和函数声明提升到全局作用域的顶端,即所谓的变量提升和函数提升,划重点只是提升变量声明,并不将赋值初始化提升。 第二步骤是运行代...
  • 变量提升 在es6之前,js作用域分:全局作用域和函数作用域 在javascript中,定义的变量,变量名会提升到 ‘当前作用域’ 顶部,此时该变量为undefined,未赋值,赋值是在js原位置。...函数提升 在js中,函数分
  • JS中的函数提升和变量提升

    千次阅读 2018-03-24 23:22:14
    变量提升和函数提升:就是将变量声明或者函数全部代码提升到当前作用域(全局作用域或函数作用域)最开始的部分。JavaScript中函数域为最小域范围;for循环、while循环、if语句、switch语句的“{}”不是作用域。注意...
  • 函数提升3. 函数优先二、暂时性死区三、总结 通常在直觉上我们会认为代码执行时是从上到下按顺序执行的,但在 JavaScript 中(就同步代码而言),这并不完全正确。 小二,上栗子! 实例 1: a = 2; var a; console....
  • 其实之前虽然刚开始学习JavaScript的时候经常看到function add(){}、var add=function(){}、function(){}之类的这种写法,但是具体是什么叫什么却没有去考虑过这个问题……function add(){}这种写法叫做函数声明var...
  • js的变量提升和函数提升 一、变量提升  在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的...
  • 变量提升 函数提升
  • 什么是变量提升?什么是函数提升

    万次阅读 多人点赞 2019-01-09 16:08:09
    在js中只有两种作用域,全局作用域和函数作用域,在ES6之前,js是没有块级作用域。 JavaScript 代码的执行分为两个阶段。第一个阶段在当前词法环境...只有函数声明才存在函数提升。 JavaScript 仅提升声明,而不...
  • js 变量、函数提升

    千次阅读 2015-07-30 13:24:27
    js 变量、函数提升 先简单理解下作用域的概念,方便对变量与函数提升的概念的理解 function foo() { var x = 1; if (x) { var x = 2; } console.log(x); } foo();// 2结果为2,可见js中并没有块级作用域的...
  • 转载至https://www.cnblogs.com/oxiaojiano/p/7918967.html一、变量提升在ES6之前,JavaScript没有块级...(1) 创建函数有两种形式,一种是函数声明,另外一种是函数字面量,只有函数声明才有变量提升console.log(a...
  • 首先来段总结: 引擎在读取js代码的过程中,分为两步。第一个步骤是整个js代码的解析读取,第二个步骤是执行。...2.函数提升的优先级大于变量提升的优先级,即函数提升在变量提升之上。 记住这两句话,就可...
  • 变量提升函数提升

    万次阅读 2021-08-25 20:13:19
    会出现函数提升 fn2() function fn2 (){ console.log("fn2()") } 3、 表达式定义的不遵循函数提升 通过function定义(声明)的函数,在之前就可以调用,不是函数声明的方式定义的函数不遵循函数提升 值:函数定义...
  • 函数声明与函数表达式的提升问题

    千次阅读 2019-03-29 16:59:51
    函数a是函数声明,执行的是函数提升,实际效果是 function a() { console.log(1); } a(); 即会把整个函数声明提到作用域顶端 而函数b是函数表达式,执行的是变量提升,实际效果是 var b; b(); b = function() {} ...
  • 变量提升/函数提升

    千次阅读 2016-12-06 19:33:25
    很多人在初学JS接触到变量,函数的时候,总会碰到一个很棘手的问题----变量/函数提升. 然而变量提升之所以存在疑点,是因为它涉及到了作用域(scoping)的问题.所以在讲变量/函数提升之前,我们先来研究一下作用域的问题.
  • JS函数简单的底层原理 (个人理解): ...4.在预解析阶段,会给var申明的变量,和函数提升的函数,分配内存空间(堆内存或者是栈内容空间).这里注意this的指向问题. 5.在函数中, 如果有 不用 任何声明符号声
  • 1.首先最常见的一种变量提升 console.log(a); //输出 undefined var a=10; console.log(a) // 输出 10 var 有提升的作用其实上面的代码会变成会变成 var a; console.log(a); //输出 undefined a=10; //赋值留...
  • 一、变量提升  在ES6中提出了块级作用域,用var声明的变量,起作用域应为对整个块都起作用,所以会跑偏;而且使用var声明的变量会出现“变量提升”现象。 那么什么是变量提升呢?...只有函数声明才存在函数提升!如:

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 522,852
精华内容 209,140
关键字:

函数提升