JavaScript笔记(自用)——03变量
笔记均参考自JavaScript高级程序设计
ECMAScript变量可以用于保存任何类型的数据。有三个关键字可以声明变量:var、const和let。(let和const只能在ES6以后本版使用)
var 关键字
定义变量可以使用 var 操作符(var是一个关键字),后跟一个变量名:
var messagr; //声明了一个名为message的变量,可保存任意类型数据
//不初始化的情况下,会保存一个特殊的值undefind
初始化变量:
var message="hi";
赋值
message=100;
var声明作用域
在function外部定义为全局变量 在function内部定义为局部变量 没有var直接给标识符赋值为全局变量
<script>
var message="hi"; //全局变量
function test(){
b = "我是全局变量b"; //全局变量,但不推荐,严格模式下会抛出异常
var a=3; //局部变量
console.log(a); //3
}
console.log(message); //“hi”
console.log(b); //“我是全局变量b”
console.log(a); //出错!
</script>
定义多个变量可以在一条语句中用逗号分隔每个变量(及初始化):
var snake="si",
age=18,
message="haha";
var声明提升
提升是指把所有的变量声明都拉到函数作用域的顶部。
function foo(){
console.log(age);
var age=26;
}
foo(); //undefined
等价于
function foo(){
var age;
console.log(age);
gae=26;
}
foo(); //undefined
let声明
let和var的作用差不多,但有非常重要的区别: let声明的范围是块作用域,var声明的范围是函数作用域
if(true){
var name='haha';
console.log(name); //haha
}
console.log(name); //haha
if(true){
let age=18;
console.log(age); //18
}
console.log(age); //ReferenceError: age is not defined(age没有定义)
这里age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部 块作用域是函数作用域的子集,因此适用于var的作用域限制也同样适用于let
let不允许同一个块作用域中出现冗余声明。这样会导致报错:
var name;
var name;
let age;
let age; //SyntaxError: Identifier 'age' has already been declared
//即 SyntaxError: 标识符age已声明过了
JavaScript引擎会记录用于变量声明的标识符及其所在的块级作用域,因此嵌套使用相同的标识符不会报错。因为同一个块中没有重复声明
var name='lan';
console.log(name); //lan
if(true){
var name='jing';
console.log(name); //jing
}
let age=30;
console.log(age); //30
if(true){
let age=18;
console.log(age); //18
}
对声明冗余的变量不会因为混用let和var受影响。这两个关键字声明的并不是同类型的变量,它们只是指出变量在相关作用域如何存在。
var num1;
let num1; //SyntaxError
暂时性死区
let与var的另一个重要区别就是let声明的变量不会在作用域中被提升
在解析代码时,javascript引擎也会在意出现在块后面的let声明,在此之前不能以任何方式来引用未声明的变量。
在let被声明之前执行的瞬间被称为“暂时性死区” ,在此阶段引用任何后面才声明的变量都会抛出ReferenceError
//name会被提升
console.log(name); //undefined
var name='lan';
//age不会被提升
console.log(age); //ReferenceError: age is not defined
let age=18;
全局声明
使用let在全局作用域中声明的变量不会成为window对象的属性 (var声明的变量则会) *注意:let声明任然是在全局作用域中发生的 ,相应的变量会在页面的生命周期内存续。为了避免SyntaxError,必须确保页面不会重复声明同一个变量 。
var name='lan';
console.log(window.name); //lan
let age=26;
console.log(window.age); //undefined
for循环中的let声明
在let出现之前,for循环定义的迭代变量会渗透到循环体外部
for(var i=0;i<5;++i){
//循环逻辑
}
console.log(i); //5
let之后,这个问题就消失了。(作用域)
for(let i=0;i<5;++i){
//循环逻辑
}
console.log(i); //ReferenceError:i没有定义
对迭代变量的奇特声明和修改:
for(var i=0;i<5;++i){
setTimeout(()=>console.log(i),0);
}
//输出为:5,5,5,5,5
-
在退出循环时,迭代变量保存的是导致循环退出的值。在之后的执行超时逻辑时,所有的i都是同一个变量。 -
使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。 for(var i=0;i<5;++i){
setTimeout(()=>console.log(i),0);
}
//输出为:0,1,2,3,4
const声明
const声明的变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。
const person={};
person.name='lan'; //ok
-
javascript引擎会未for循环中的let声明分别建立独立的变量实例,const与let变量相似,也不能const来声明迭代变量(迭代变量会自增): for(const i=0;i<10;++i); //TypeError:给常量赋值
-
可以只用const声明一个不被修改的for循环变量。即:每次迭代只是创建一个新变量。 let i =0;
for(const j=7;i<5;++i){
console.log(j);
}
//7,7,7,7,7
声明风格建议
- 不使用var
只使用let和const有助于提升代码质量,因为变量有明确的作用域、声明位置、不变的值 。 - const优先,let次之
- 使用const声明可以让浏览器运行时强制保持变量不变。
- 也可以让静态代码分析工具提前发现不合法的赋值操作。
- 有利于后期维护。
|