变量的定义:ECMAScript 中变量是用来保留任意数据类型的命名占位符。目前有三种申明变量的形式:var、let、const。
一、var 申明
var message;
// 通过 var 关键字前面跟着变量名的形式来申明变量, 能够保留任意类型的数据,在没有赋值的状况下,message 的值为 undefined
var 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) // undefined
var name = 'Tom'
// 在申明变量 name 前就应用了 name 变量,并没有报错,而是为 undefined
function foo() {console.log(age);
var age = 26;
}
foo(); // undefined
// 同样在函数作用域里,也会存在变量晋升
二、let 申明
let 关键字创立变量的形式跟 var 是一样的,区别在于 let 申明的范畴是块作用域,
而 var 申明的范畴是函数作用域。以下是 let 跟 var 创立变量的区别
1、let 创立变量不存在变量晋升
// var 的状况
console.log(foo); // 输入 undefined
var foo = 2;
// let 的状况
console.log(bar); // 报错 ReferenceError
let 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);
}