var
说明
-
使用var声明变量,在方法内部是局部变量,在方法外部是全局变量
-
没有使用var声明的变量,在方法内部或外部都是全局变量,但如果在方法内部声明,在方法外部使用之前需要先调用方法,告知系统声明了全局变量后方可在方法外部使用
-
不使用var关键字声明的全局变量,不会前置
一、var声明变量的问题
-
(1)允许重复的变量声明:导致数据被覆盖
-
(2)变量提升:怪异数据访问(闭包问题)
-
怪异数据访问:即变量提升导致块级作用域内的变量可以在外部访问到
-
闭包问题
var body = document.getElementsByTagName('body')[0]; for (var i = 1; i <= 10; i++) { var btn = document.createElement('button'); btn.innerHTML = '按钮' + i; body.appendChild(btn); btn.onclick = function () { console.log(i); //每次都是输出11 } } //闭包 for (var i = 1; i <= 10; i++) { var btn = document.createElement('button'); btn.innerHTML = '按钮' + i; body.appendChild(btn); (function(s) { btn.onclick = function() { console.log(s); } })(i) } //或在使用let声明变量 for (let i = 1; i <= 10; i++) { var btn = document.createElement('button'); btn.innerHTML = '按钮' + i; body.appendChild(btn); btn.onclick = function () { console.log(i); } }
-
-
(3)全局变量挂载到全局对象,全局对象成员污染问题
console.log(window.name); var name = 'abc'; console.log(window.name);
二、let声明变量
-
(1)let声明的变量不会挂载到全局对象
let a = 123; console.log(window.a);//underfined
-
(2)let不允许在当前作用域内重复声明,在块级作用域中用let声明的变量在作用域外不能访问
-
重复声明变量会报错
let a = 123; let a = 456; //报错
-
作用域外访问块级作用域的变量会报错
{ let a = 123; } console.log(a);//报错
-
-
(3)使用let不会有变量提升,因此不能再let定义变量之前使用该变量
-
在变量声明前去访问该变量会报错
console.log(a); //报错,该错误提示为:不能在a初始化之前访问,而不是a未被定义 let a = 123; //该错误提示为:不能在a初始化之前访问,而不是a未被定义,可见在底层实现上,let声明的变量实际上是提升了,拓展如下
-
-
扩展如下
-
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
-
(1)底层实现上,let声明的变量实际上也会有提升,但是提升后会将其放到“暂时性死区”,如果访问的变量位于暂时性死区,则报错如图2-2-3,当代码运行到该变量的声明语句时,会将其从暂时性死区中移出
-
(2)在循环中,用let声明的循环变量会被特殊处理,每次进入循环体都会开启一个新的作用域,并且将循环变量绑定到该作用域,则每次循环使用的是一个全新的循环变量
-
(3)在循环中,使用let声明的循环变量在循环结束后会销毁
-
-
解决闭包问题
let body = document.getElementsByTagName('body')[0]; for (let i = 1; i <= 10; i++) { let btn = document.createElement('button'); btn.innerHTML = "按钮" + i; body.appendChild(btn); btn.onclick = function () { console.log(i); } }
三、使用const声明变量
-
const和let基本相同,区别在于用const声明的变量,必须在声明时赋值,而且不可以重新赋值
-
【例】在声明时未赋值,报错
const a; a = 1; console.log(a); //报错,该报错信息为:在变量声明时没有初始化
-
【例】修改const声明的变量,报错
const a = 1; a = 2; console.log(a); //报错
-
实际上,在开发中应该尽量使用const来声明变量,以保证变量的值不会随意篡改,原因如下:
-
根据经验,开发中的很多变量,都是不会更改的,也不应该更改
-
后续的很多框架或者第三方JS库,都要求数据不可变,使用常量可以一定程度上保证这一点
-
【注】
-
(1)常量不可变,是指声明的常量的内存空间不可变,并不保证内存空间中的地址指向的其他空间不可变【例】
const a = { name: 'jwh', age: 18 }; a.name = 'zdw' console.log(a); //结果:{name:"zdw",age:18}
-
(2)常量的命名
-
特殊的常量:该常量从字面意义上,一定是不可变的,比如圆周率、月地距离或者其他一些绝不可能变化的配置。通常,这些常量的名称全部使用大写,多个单词之间用下划线分割
-
普通的常量:命名规则与之前相同
-
-
(3)在for循环中,循环变量不可以使用常量【例】
var arr = [{name:'jwh'},{age: 18}] for (const i = 0; i < arr.length; i++) { console.log(arr[i]); } //结果,会报错
-
例】for in循环可以用const声明变量
var obj = { name: 'jwh', age: 18 } for(const prop in obj) { console.log(obj[prop]); } //结果,jwh //18
-