变量,常量介绍,变量与常量的区别

我被代码海扁 @codebeatme-s @103466775
阅读 7:41·字数 2309·发布 

前提
阅读本节的前提是对值和数据类型的概念有所掌握,你可以查看值,数据类型介绍一节来了解他们。

变量

在代码层面,变量可以被认为是值的存储容器,无论是哪种语言,这样的解释都没有问题。变量存储的具体值一般是可以变化的,比如,一个关于年龄的变量,开始时为0,经过计算后可能变为100

为何使用变量?
在编写代码的过程中,人们需要通过变量来访问值,这使得值具有了明确的含义,比如,这个数字表示年龄,那个数字表示物品数量。如果没有变量,那一切会像直接操作处理器一样,开发人员会头疼,因为他忘记了那些数字具体表示什么。

什么是变量的标识符?
变量的标识符也就是变量在代码中的名称,要使用变量就需要书写其对应的标识符,这是一个愚蠢的问题,如果你希望某个人应答你,当然最好是说出对方的名字。

变量赋值

在读取一个变量之前,一般需要为该变量赋值,这是理所当然的,因为读取变量中的值的前提是存在一个值。

对于一些语言,比如 JavaScript,如果开发人员在定义变量时,未对其进行赋值,那么该变量将获得一个默认值。而另一些语言,比如 Python,则会把未明确赋值的变量视为未定义。

在下面的 JavaScript 代码中,变量age被赋予默认值undefined

variables_and_constants.js
// 定义变量 age,他将获得默认值 undefined
let age
// 显示变量 age 的值
console.log(age)
undefined

JavaScript 中的 undefined 不表示变量不存在
JavaScript 中的undefined通常用于描述未定义,但变量的值为undefined并不代表该变量不存在,当你真的访问一个不存在的变量时,通常会导致异常ReferenceError

在 JavaScript 中读取未定义变量student,将引发异常ReferenceError

variables_and_constants.js
// ERROR 变量 student 没有被定义过,这会导致异常
console.log(student)
ReferenceError: student is not defined

变量类型

变量的类型用于规定其值应有的数据类型,由于隐式转换的存在,为变量分配的值的数据类型可以和变量的类型不同,数据类型之间的转换将自动进行,在符合一定条件的情况下。

并非所有的编程语言都支持声明变量的类型,尤其是对于非类型安全的语言,他们的变量将接受任意数据类型的值。

不指定变量类型带来了灵活性
不指定变量类型,使得代码更具灵活性,变量对应的值成为了一种判断依据,你可以根据值的数据类型,来决定接下来的操作。当然,这样的做法带来了安全隐患,变量中的值可能是不希望或无法处理的类型。

变量种类

依据其值是存储在栈还是堆中,变量可以分为值类型变量和引用类型变量。而从存储值这一功能来看,参数,字段也应被归入变量这一概念。你可以将参数理解为函数拥有的变量,将字段理解为类或实例拥有的变量。

栈,堆
想要详细了解栈,堆,值类型变量,引用类型变量等概念,你可以查看栈,堆,指针介绍一节或堆和引用一段。

函数是一种特殊的变量?
编程语言维护了一个或多个关于标识符的“表格”,他不仅包括了变量名称,还包括函数的名称,通过这些“表格”,可以判断某个变量或函数是否未定义。从这个角度来看,函数也是一种变量,只不过这种变量存储了比较特殊的值,他们是处理数据的某种功能。

这解释了为什么在不少语言中,可以将函数赋值给变量,或将函数作为参数传递。

在 JavaScript 中,我们将函数sendToClient赋值给变量fn,并通过fn调用了该函数。

variables_and_constants.js
// 一个将信息发送给客户的函数
function sendToClient(message) {
	console.log(`发送给客户:${message}`)
}

// 将函数 sendToClient 赋值给变量 fn let fn = sendToClient // 通过变量调用函数 fn('今天天气不错!')
发送给客户:今天天气不错!

变量的传递

当你将一个变量赋值给另一个变量时,默认会发生值传递,这使得两个变量是相对独立的。至于引用传递,他会使一个变量成为另一个变量的别名。

栈,堆
想要更好的了解值传递和引用传递,你可以查看栈,堆,指针介绍一节或堆和引用一段。

常量

与变量相反,常量似乎对应了无法改变,在代码中你不能对已经赋值的常量再次赋值,除非将其重新定义,如果允许的话。

需要指出,你不能将常量视为变量的一种特例,因为在某些情况下,常量并不会真实的存储值。

编译时常量

如果一个常量的值,在编译时可以确定,那么该常量被称为编译时常量。编译时常量在真实的运行过程中是不存在的,他们仅作为一种占位符而存在,并在编译时被替换为其值的字面量。

当然,某个表达式能否被运算为确定的值,需要视语言对应的编译器而定。

在下面的 C# 代码中,A1是一个正确的编译时常量,因为13可以在编译时确定。A2同样是一个正确的编译时常量,因为表达式13+A1可以在编译时计算出确定结果。A3是一个不正确的编译时常量,因为变量b1的值无法在编译时确定。

*.cs
// A1 是编译时常量
const int A1 = 13;

// A2 是编译时常量,因为表达式可以在编译时计算出结果 const int A2 = 13 + A1;
int b1 = 0; // ERROR A3 是一个错误的编译时常量,因为 b1 的值在编译时是无法确定的 const int A3 = b1;

什么是编译时?
编译时是指正在编译的时候,而所谓的编译,是指将代码转换为可被目标运行的内容。这里的目标可以是操作系统,或某种语言的运行环境,比如,Java 虚拟机。

根据目标的不同,编译内容会拥有不同的文件格式,比如,Windows 的可执行文件,或 Java 虚拟机的字节码文件等。

运行时常量

与编译时常量不同,运行时常量的值不需要在编译时确定,因此,运行时常量更像是一种只读的变量,他存在于真实运行过程,并存储真实的值。

在下面的 JavaScript 代码中,result是一个运行时常量,其值由运行过程中的xy的值确定。

variables_and_constants.js
for (let x = 0; x < 2; x++)
	for (let y = 0; y < 2; y++) {
		// 运行时常量,其值在运行时确定
		const result = x * y

console.log(result) }
0
0
0
1

源码

variables_and_constants.js·codebeatme/programming·GitHub
variables_and_constants.cs·codebeatme/programming·GitHub