变量的定义:ECMAScript中变量是用来保留任意数据类型的命名占位符。目前有三种申明变量的形式:var、let、const。

一、 var申明

var message;// 通过var关键字前面跟着变量名的形式来申明变量,能够保留任意类型的数据,在没有赋值的状况下,message的值为undefinedvar name = 'Jack'name = 12// 这里创立了变量名为name,并保留字符串类型的数据'Jack',只是一个简略的赋值而已。随后,不仅能够扭转保留的值,也能够扭转值的类型。

1、var申明作用域
留神:应用 var 操作符定义的变量会成为蕴含它的函数的局部变量,不能在函数内部调用。

function test() {  var message = "hi"; // 局部变量} test(); console.log(message); // 出错!//应用 var在一个函数外部定义一个变量,就意味着该变量将在函数退出时被销毁,不能在内部调用。
function test() {  message = "hi"; //全局变量} test(); console.log(message); // "hi"// 去掉之前的 var 操作符之后,message 就变成了全局变量,能够在函数内部被调用

留神:在全局作用域下,通过var关键字创立的变量,会在window对象上增加相应的属性

var name = 'jack'console.log(window.name) //'jack'

2、var变量晋升
变量晋升其实就是,能够在以后作用域下应用申明前的变量,其值为undefined。

console.log(name) // undefinedvar name = 'Tom'// 在申明变量name前就应用了name变量,并没有报错,而是为undefinedfunction foo() {  console.log(age);  var age = 26; } foo(); // undefined// 同样在函数作用域里,也会存在变量晋升

二、let申明
let关键字创立变量的形式跟var是一样的,区别在于let 申明的范畴是块作用域,
而 var 申明的范畴是函数作用域。以下是let跟var创立变量的区别

1、let创立变量不存在变量晋升

// var 的状况console.log(foo); // 输入undefinedvar foo = 2;// let 的状况console.log(bar); // 报错ReferenceErrorlet bar = 2;

2、let会存在暂时性死区
只有块级作用域内存在let命令,它所申明的变量就“绑定”(binding)这个区域,不再受内部的影响。

var num = 123;if (true) {  num= 'abc'; // ReferenceError  let num;}//下面代码中,存在全局变量num,然而块级作用域内let又申明了一个局部变量num,导致后者绑定这个块级作用域,所以在let申明变量前,对num赋值会报错。

ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令申明的变量,从一开始就造成了关闭作用域。但凡在申明之前就应用这些变量,就会报错。

总之,在代码块内,应用let命令申明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

3、不能反复申明
let不容许在雷同作用域内,反复申明同一个变量。

// 报错function func() {  let a = 10;  var a = 1;}// 报错function func() {  let a = 10;  let a = 1;}function func(arg) {  let arg;}func() // 报错function func(arg) {  {    let arg;  }}func() // 不报错

4、let会存在块级作用域
在大括号{ }外面应用let创立变量,此时大括号{ }会造成一个块级作用域,内部不能应用块级作用域下创立的变量,会报错,而通过var创立变量,不存在块级作用域。

if (true) {  let age = 26;  console.log(age); // 26 } console.log(age); // ReferenceError: age 没有定义if (true) {  var name = 'Matt';  console.log(name); // Matt } console.log(name); // Matt

块级作用域解决以下两种场景:
1、内层变量可能会笼罩外层变量

var tmp = new Date();function f() {  console.log(tmp);  if (false) {    var tmp = 'hello world';  }}f(); // undefined

2、用来计数的循环变量泄露为全局变量

var s = 'hello';for (var i = 0; i < s.length; i++) {  console.log(s[i]);}console.log(i); // 5

上述两种场景都能够通过let创立变量造成块级作用域来解决

5、let创立变量不成成为window的属性

let name = 'ken'console.log(window.name)  // undefined

const申明

const创立变量跟let一样,都会造成块级作用域,都不能反复申明。惟一的区别就是,const申明一个只读的常量,一旦申明,常量的值就不能扭转。

const name = 'jack'name = 'tom' // TypeError: Assignment to constant variable.const foo;// SyntaxError: Missing initializer in const declaration// const申明变量肯定要赋值,不然会报错

以上就是我集体总结进去申明变量的三种形式及其区别,上面再做几道题目来坚固以下知识点

if(1){   a = 1;   console.log(a)}console.log(a)if(1){  var b = 2;  console.log(b)}console.log(b)if(1){  let c = 3;  console.log(c)}console.log(c)
var a = [];for (let i = 0; i < 10; i++) {    console.log(i);    a[i] = function () {        console.log(i);//执行此代码时,for循环曾经执行结束。    };}a[6]();
if (true) {  tmp = 'abc';    console.log(tmp);  //在let申明变量tmp之前就应用该变量,会报错。  let tmp;   console.log(tmp);    tmp = 123;  console.log(tmp);  }