javascript之变量声明

JavaScript是一门弱类型语言,它并不像其他强类型语言那样有多种变量类型的声明形式,如:int, double, string… 等,在JavaScript中声明变量统一使用 var 关键字。

例如想要声明一个整数来使用,可以使用 var num = 1; 这样的语句,声明一串字符串也一样 var str = 'string'; ,声明一个布尔值、数组、对象都是使用 var 这个关键字: var boo = true; var arr = [1,2,3]; var obj = { x: 1, y: 2};

1
2
3
4
5
var num = 1; // 声明一个整数
var str = "string"; // 声明一串字符串
var bool = true; // 声明一个布尔值
var arr = [1,2,3]; // 声明一个数组
var point = { x: 1, y: 2 }; // 声明一个对象

在ES5标准之前,只有 var 这一个关键字用来声明一个可以使用的变量(函数暂不讨论)。而在ES6标准中,在此之上添加了两个新的声明变量的关键字,letconst。严格说起来应该是一个声明变量,一个声明常量, const 就是用来声明常量的关键字。

let与var有什么不同?

这需要从变量的作用域说起。在ES5标准之前,JavaScript中只有两种作用域:全局作用域与函数作用域。全局作用域的变量可以在代码运行中的任何位置访问到,而函数作用域的变量只有在该函数内部能够访问到。而在ES6标准中新增了一个块级作用域的概念,let关键字就是对应块级作用域的概念的变量声明。通过let声明的变量只有在声明时所在的块级作用域的范围内能访问,所谓块级作用域指的是代码中被{}包裹起来的代码(对象除外),函数体也属于代码块。

letvar 另一个不同的地方在于:

  • var 声明的变量可以重复声明,但只有第一次声明有效,且有声明提升;

  • let 声明的变量不能再次声明,否则会报错,且let声明的变量并没有声明提升。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
var x = 1;
let y = 2;
}
console.log(x); // 1
console.log(y); // ReferenceError: y is not defined
// let声明的变量在他所在的块级范围之外无法访问
/* --------------------------------------- */
console.log(a);
// undefined: 因为var声明有变量名提升,所以运行代码时,
// 系统就知道a是一个变量,只是这个变量并没有被赋值,因此是undefined
var a = 1;
console.log(b);
// ReferenceError: b is not defined
// 因为let声明没有变量名提升,所以运行到这句代码时,
// b还没有定义,不能作为一个变量使用
let b = 2;
/* --------------------------------------- */
var c = 1;
var c = 2;
console.log(c); // 2
let c = 3; // SyntaxError: Identifier 'c' has already been declared
// let 无法重复声明已有变量
console.log(c);

const常量

所谓常量,与变量相反。变量就是可以改变的量,而常量则是一旦声明,就无法改变的量。有些数据在使用过程中是不会改变的,甚至有些就是固定不变的值,如圆周率PI,像这样的数据,使用 var 声明,之后一直不做改动自然也是不算错的,但是使用 const 声明的话,更能够表达出符合的语义,用 const PI = 3.14; 代替 var PI = 3.14; 更能让人清楚地知道这是一个常量。

const声明的变量的作用域范围同let关键字,也是声明变量所在的块级作用域,用const声明的变量也不能重复声明,且没有变量声明提升,另外不能通过赋值来改变常量的值。

基于这几点,在声明一个常量的时候就要将这个常量的值赋给它,而不能先声明一个没有值的常量,再在之后赋值。

1
2
3
4
5
const PI = 3.14;
const RWBY;
RWBY = ["ruby","weiss","blake","yang"]; // SyntaxError: Missing initializer in const declaration
// 虽然错误是在重新给常量赋值时抛出的,也就是说 const RWBY; 这一步并没有错
// 但是很显然这样的语句毫无意义,所以通常声明一个常量时应该直接将值赋予该常量

关于变量声明提升

JavaScript是解释型语言,解析一句执行一句,为了提高效率,在代码解析执行之前,有一个预解析的过程。在预解析时,代码并不会执行,系统只会检查当前作用域(函数内部的代码不会检查,只有在调用函数时,才会重复 “预解析->执行” 这样的步骤)的代码有没有语法上的错误和代码中的变量声明关键字 var 和函数声明的关键字 function

在遇到这两种声明时,系统会在内存中预先记录下声明的变量名和函数名,也就是标识符。在预解析结束后,运行代码之前,系统就得到了有哪些标识符是可以作为变量来使用的,如果使用了系统未记录的标识符,也就是没有声明的变量,这时系统就会抛出一个引用错误 ReferenceError: xxx is not defined

在预解析过程中,如果遇到了同一个标识符多次声明,是不会多次记录的,只会记录第一次。如果同一个标识符既有变量声明var,又有函数声明function,最终记录下来的标识符是一个函数,遵循的原则是先有什么就记录什么,函数声明会记录两件事,一个同变量声明,记录该标识符可以使用,第二个记录该标识符指向一个函数。
所以有说法 函数是JavaScript中的一等公民
但要知道该记录只保持在预解析结束,运行代码之前。
在运行代码过程中,需要根据实际情况判断标识符到底是一个变量还是一个函数。