终于弄明白了js的变量作用域

JavaScript变量作用域

变量提升概念

1、变量提升

在js中,用var声明的变量,解释器都会把声明提升到它所在作用域的顶端去执行,到我们代码所在的位置来赋值

代码示例1:

使用var声明的变量会被提升到所有代码执行之前

console.log(x)
var x = 123;

解析器执行时,代码实际是下面这种:

var x;
console.log(x);//所以此时代码不汇报 x is not defined,而是输入undefined
x = 123;
2、函数提升(变量提升的变种)

同理,用var声明的函数,解释器都会把声明提升到它所在作用域的顶端去执行,到我们代码所在的位置来赋值

console.log(func);
func();//执行时报错!
var func = function(){
    console.log('我是一个函数!')
}

上线那段代码执行时会报错,原因如下,解释器执行改代码的逻辑顺序:

var func;
console.log(func);//输出undefined
func();//因为此时func还未被实际赋值为函数(函数也是对象嘛,也就是说还没有被实例化),只是个undefined,undefined对象不是个函数,         执行报错
func = function(){
    console.log('我是一个var关键字声明的函数!')
}
​
运行结果为:
undefined
func();//执行时报错!
^
TypeError: func is not a function
3、避免变量/函数提升方式
3.1 使用 let、const声明

代码所在位置及声明处,此代码未执行时,变量不会被声明

3.2 函数使用function声明
console.log(func);
func();
function func(){
    console.log('我是一个function关键字声明的函数!');
}
​
输出结果:
[Function: func]
我是一个function关键字声明的函数!

解释器在执行上面代码时,逻辑顺序如下:

//会把function声明的函数对象提升到所有代码之前
function func(){
    console.log('我是一个function关键字声明的函数!');
}
console.log(func);
func();

顶层对象(window/global)

1、作用范围

整个浏览器(或者说js解释器)的代码都在该对象作用范围下

  • 例如:document、history、navigator等

  • 有很多默认的属性和方法

2、给window/global添加属性

注意:顶层对象也是个对象,js中的Object可以随便添加删除属性,这一点不像java

  1. 在全局作用域中使用var、function,都是在给window、global添加属性

  2. function关键字定义的可以说添加方法,怎么说都行

  3. 无论在任何地方,不使用任何关键字,直接给变量赋值,都相当于给顶层对象添加了属性

3、代码解释
name = 'wugb';
if(true){
    age = 18;
}
console.log(name);
console.log(age);
输出结果:
wugb
18

为什么在if语句中定义的age变量也能正常输出呢?因为在解释器中,上面的代码是这样的

//浏览器
window.name = 'wugb';
if(true){
    window.age = 18;
}
console.log(window.name);
console.log(window.age);

即:如果未使用任何关键字进行声明,则变量直接被window对象添加为自身属性,在之后使用到该对象时,如果根据 块-->函数-->全局这条链都找不到定义的话,就会直接从顶层对象中尝试获取该属性值

4、避免变量作用域混乱
4.1、避免或禁止使用无关键字定义变量的方式
4.2、如果需要给顶层对象赋值,直接 window.变量名 = '变量值',简单直观

一、ES5及之前版本

1、定义方式:
1.1 var key = value;
1.2 直接 key = value;
var name = 'wugb';
或
name = 'wugb';
区别见2.2
2、var - 主动声明唯一关键字!

在老版本中,js定义变量只有一个关键字 ---- var

2.1.默认作用域:函数之内

注意:window是浏览器默认对象,也可以说是函数

2.2 在哪定义
①、全局作用域

无论用不用var,都会自动成为window对象的属性

区别:

-- var关键字会导致变量提升,哪怕没赋值都可以用,只不过这会儿自身是undefined

-- 而未用任何关键字定义的变量 没办法提前使用,使用则报错 xxx is not defined,因为它没有变量提升这一重buff么

②、函数(注意:对象也是个函数)

整个函数体内都可以用,原因:变量提升

因为js解释器在执行js代码时,会把var修饰的变量都提升到作用域任何代码前去声明,就导致了该变量对函数内的任何一个地方都可见

showMyName();
function showMyName(){
    console.log(name);
    if(true){
        var name = 'wugb';
    }
    if(true){
        console.log(name);
    }
}
输入结果让人大吃一惊:
undefined
wugb
问题1:为何执行showMyName()时,没有报错showMyName is not undefined?

答:因为function修饰的方法会变量提升,所以其方法的声明在代码执行之前

问题2:为何第一次打印name时,没有报错name is not undefined?

答:因为var定义的变量会出现变量提升现象,所以早在第一行输出代码前,name 已经被声明了,只是还未被赋值

问题3:为何第二次打印name时,明明已经不在同一个代码块中了,也不报错呢?在java中肯定报错了!

答:同样是因为变量提升现象,name已经被声明,且对整个函数内的任何地方都可见,所以第二次输出不会报错,甚至还被赋值过。

//实际在js解释器中,上述代码是这么执行的
function showMyName(){
    var name;
    console.log(name);
    if(true){
        name = 'wugb';
    }
    if(true){
        console.log(name);
    }
}
showMyName();

1、将showMyName函数的声明提升到最上方

-- 此时该方法已经可以执行了

2、将函数内的var修饰的name变量提升到最上方声明

-- 此时name属性已经在整个函数内都可见了,只要是函数内的代码,都可以访问到name变量

3、所以:第一次打印:undefined,第二次打印:wugb

2.3 直接key = value

相当于给顶层对象加属性,不建议这种方式

二、ES6及之后版本

var --- 和之前一样,整个作用域内变量提升,从而整个作用域(全局/函数)内有效

let、const ---定义变量或常量,没有变量提升,所以是块级作用域,和java一样,就不多说了

直接key = value,和之前版本一样,都是给顶层对象添加/修改属性,也不多说了

总结:

有变量提升特性的关键字(var),作用域就是全局/整个函数内

没有变量提升特性的关键字(let/const),作用域就是一个代码块,和java一样

其实就是相当于js多了个变量提升的概念,其他的和java都一样

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值