js变量作用域--变量提升

1、JS作用域

在ES5中,js只有两种形式的作用域:全局作用域和函数作用域,在ES6中,新增了一个块级作用域(最近的大括号涵盖的范围),但是仅限于let方式申明的变量。

2、变量声明

1 var x;      //变量声明
2 var x=1;    //变量声明并赋值
3 x = 1;    // 定义全局变量并赋值

3、函数声明

function fn(){};     //函数声明并定义
var fn = function(){};    // 实际上是定义了一个局部变量fn和一个匿名函数,然后把这个匿名函数赋值给了fn

4、变量提升

var tmp = new Date();
function fn(){
    console.log(tmp);  //Wed Jul 12 2017 22:11:56 GMT+0800 (中国标准时间)
}fn();

a情形

var tmp = new Date();
function fn(){
    console.log(tmp);    //undefined
    if(false){
        var tmp = ‘hello‘;
    }
}
fn();

b情形

var tmp = new Date();
function fn(){
    console.log(tmp);    //undefined
    if(true){
        var tmp = ‘hello‘;
    }
}
fn();

c情形

从上面可以看到,b情形和c情形为什么不同于a情形,就是因为变量提升了(ps: c情形不同于b情形的是判断条件为true,但是这里不是看代码有没有被执行,是看变量有没有被定义)。fn函数里面定义了同名变量tmp,无论在函数的任何位置定义tmp变量,它都将被提升到函数的最顶部。等同于下面情形:

var tmp = new Date();
console.log(tmp);
function fn(){
        var tmp;
    console.log(tmp);    //undefined
    if(false){
        var tmp = ‘hello‘;
    }
}
fn();

这里需要说明的是,虽然所有的申明(包括ES5的var、function,和ES6的function *、let、const、class)都会被提升,但是var、function、function *和let、const、class的的提升却并不相同!具体原因可以看这里的说明(大体的意思是虽然let,const,class也被提升了,但是却并不会被初始化,这时候去访问他们则会报ReferenceError异常,他们需要到语句执行的时候才会被初始化,而在被初始化之前的状态叫做temporal dead zone)。

因为这样的原因,推荐的做法是在申明变量的时候,将所用的变量都写在作用域(全局作用域或函数作用域)的最顶上,这样代码看起来就会更清晰,更容易看出来那个变量是来自函数作用域的,哪个又是来自作用域链。

5、重复声明

var x = 1;
console.log(x);
if(true){
    var x = 2;
    console.log(x);
}
console.log(x);

上面的输出其实是:1 2 2。虽然看起来里面x申明了两次,但上面说了,js的var变量只有全局作用域和函数作用域两种,且申明会被提升,因此实际上x只会在最顶上开始的地方申明一次,var x=2的申明会被忽略,仅用于赋值。也就是说上面的代码实际上跟下面是一致的:

var x = 1;
console.log(x);
if(true){
    x = 2;
    console.log(x);
}
console.log(x);

6、函数和变量同时提升的问题

console.log(fn);
function fn(){};
var fn = ‘string‘;

上面的输出结果其实是: function fn(){} ,也就是函数内容。

console.log(fn);
var fn = function fn(){};
var fn = ‘string‘;

这时输出结果就是undefined,知道上面的声明提升的道理就不难理解了。

总结:

要彻底理解JS的作用域和Hoisting,只要记住以下三点即可:

1、所有申明都会被提升到作用域的最顶上

2、同一个变量申明只进行一次,并且因此其他申明都会被忽略

3、函数声明的优先级优于变量申明,且函数声明会连带定义一起被提升

注意:

通过with语句,可以临时改变运行期上下文的作用域链,此时的对非var定义的变量进行访问,会首先访问with中对象的属性,然后才会向上顺着作用域链向上检查该属性。

时间: 2024-12-12 05:24:45

js变量作用域--变量提升的相关文章

JavaScript的变量作用域

http://www.cnblogs.com/rainman/archive/2009/04/28/1445687.html tag:作用域链 作用域 声明提升 全局变量 http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014344993159773a464f34e1724700a6d5dd9e235ceb7c000 tag:变量作用域 声明提升 全局作用域 命名冲突 ES6(

JavaScript&jQuery.变量作用域

变量作用域 变量的位置或影响它的作用范围,这个作用范围也叫作用域. 如果变量是在函数内声明的,那么的作用域仅在函数内,函数之外不能调用.函数调用执行完后,函数内的变量立即销毁. function getArea(length,width){     // 局部变量area,在函数调用后立马销毁     var area= length*width;     return area; } 如果变量是在函数外声明的,它的作用域是全局的,也叫全局变量.在页面被浏览器加载后,全局变量一直存于内存中,直到

MySQL数据库8(二十五)变量作用域

变量作用域 变量作用域:变量能够使用的区域范围 局部作用域 使用declare关键字声明(在结构体内:函数/存储过程/触发器),而且只能在结构体内部使用. declare关键字声明的变量没有任何符号修饰,就是普通字符串,如果在外部能够访问该变量,系统会自动认为是字段. 会话作用域 用户定义的:使用@符号定义的变量,使用set关键字. 会话作用域:在当前用户当次连接有效,只要在本连接之中,任何地方都可以使用(可以在结构内部,也可以跨库) 会话变量可以在函数内部使用 会话变量可以跨库 全局作用域 所

JS中作用域和变量提升(hoisting)的深入理解

作用域(Scoping) javascript作用域之所以迷惑,是因为它程序语法本身长的像C家族的语言.我对作用域的理解是只会对某个范围产生作用,而不会对外产生影响的封闭空间.在这样的一些空间里,外部不能访问内部变量,但内部可以访问外部变量. c语言的变量分为全局变量和局部变量,全局变量的作用范围是任何文件和函数访问(当然,对于非变量定义的其他c文件,需要使用extern关键字进行申明,使用static关键字也可以将作用范围限定在当前文件中),局部变量的作用范围就是从申明到最近的大括号涵盖的块级

js变量作用域

? 1 2 3 4 5 6 7 8 9 10 for(var i =0;i<100;i++)   {        } alert(i);//100 if(true){     var i="91d";   } alert(i);//91d ? 1 2 3 4 5 6 function add(ad1,ad2){   sum=ad1+ad2;   return sum;//如果没有用var声明局部变量,会提升为全局的变量 } alert(add(3,5)); alert(&quo

js 变量、函数提升

先简单理解下作用域的概念,方便对变量与函数提升的概念的理解 function foo() { var x = 1; if (x) { var x = 2; } console.log(x); } foo();// 2 结果为2,可见js中并没有块级作用域的概念 可以使用下面的方法创造自己的作用域,这样不会干扰到外部变量 function foo() { var x = 1; if (x) { (function() { var x = 2; }()); } console.log(x); } f

js基础之变量声明提升

变量声明的提升 这是js特有的一个特点,其他语言都没有这个特点.有些程序员挺反感这个特点的. 我们现在先去改变变量的值,然后定义变量,由于JS有一个机制,叫做变量声明的提升, javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 所以现在程序在执行前会已经看见这个程序中有一行定义变量,所以就会提升到程序开头去运行 1 2 3 4 5 6 7 8 9 var v = 'hello'; (function(){

js中的变量提升与函数提升

先看看一个简单的代码 var str='Hello World'; alert(str);//弹出 Hello World 再看一段代码: var v='Hello World'; (function(){ alert(v); })() //和我们预期的一样,还是弹出 Hello World 那么铺垫完了,继续coding var str='Hello World'; (function(){ alert(str); var str='I love coding...'; })() //出乎我们

深入理解JS中的变量及变量作用域

JS的变量有两种,"全局变量"和"局部变量". "全局变量"声明在函数外部,可供所有函数使用,(全局变量属于window)而"局部变量"声明在函数体内部,只能在定义该变量的函数体内使用. 1.全局变量:(1)直接在函数外部声明的变量   var a=3 (2)在任何位置上,声明变量时没有var关键字,而是直接赋值的变量均为全局变量     s=3 2.局部变量:(1)在函数内部声明的变量 (2)形参,参数变量天生就是局部变量