JavaScript中的常量:什么时候使用它,有必要吗?


349

我最近遇到过constJavaScript中的关键字。据我所知,它用于创建不可变变量,并且我已进行测试以确保不能重新定义它(在Node.js中):

const x = 'const';
const x = 'not-const';

// Will give an error: 'constant 'x' has already been defined'

我意识到它尚未在所有浏览器中标准化-但是我只对Node.js V8的上下文感兴趣,而且我注意到,某些开发人员/项目似乎可以在将var关键字用于同样的效果。

所以我的问题是:

  • 什么时候可以const代替var
  • 是否应该在每次声明一个不会被重新分配的变量时使用它?
  • 如果var使用它代替, const反之亦然吗?

1
这似乎尚未标准化(也许在EC6中?)。:您会在这里找到有关它的信息developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
塞巴斯蒂安·C.

Answers:


462

您的问题有两个方面:const代替使用的技术方面是var什么,以及与人相关的方面是什么。

技术差异很大。在编译语言中,常量将在编译时被替换,并且常量的使用将允许其他优化(如删除无效代码)以进一步提高代码的运行效率。最近的(松散使用的术语)JavaScript引擎实际上是在编译JS代码以获得更好的性能,因此使用const关键字将告知它们上述优化是可行的,应该完成。这导致更好的性能。

与人有关的方面与关键字的语义有关。变量是一种数据结构,其中包含预期会更改的信息。常数是一种数据结构,其中包含永远不变的信息。如果有错误的余地,var应始终使用。但是,并非必须使用声明所有在程序生存期内从未改变的信息const。如果在不同的情况下信息应该更改,var即使实际的更改未出现在代码中,也请使用该信息进行指示。


4
干杯,我以为Mozilla / Google不会无缘无故地向JS引擎添加const支持。我将确保在适用的地方使用const。
axdg 2014年

6
const对象似乎是可变的,所以我不确定JS编译器的严格程度。也许“严格使用”模式也有所不同。
鲁迪2015年

9
@Rudie您正在寻找的功能称为冻结对象。const只是防止将“变量”重新分配给另一个值。const a = {}; a = {};会在严格模式下引发错误。
Tibos 2015年

我通常使用const而不是让大多数变量使用,就像在Java中将final添加到大多数变量声明中一样。
编码

2
If there is room for error, var should always be used。如今,这不再适用,ESLint等工具立即指出了const违规情况。
vitaly-t

72

2017更新

这个答案仍然引起很多关注。值得注意的是,该答案已于2014年初发布,此后发生了很多变化。支持已成为常态。现在所有现代浏览器都支持,const因此使用起来应该很安全,没有任何问题。


2014年的原始答案

尽管有相当不错的浏览器支持,但我暂时避免使用它。来自MDN的文章const

当前const的实现是Mozilla特定的扩展,不属于ECMAScript5。它在Firefox和Chrome(V8)中受支持。从Safari 5.1.7和Opera 12.00开始,如果在这些浏览器中使用const定义变量,则以后仍可以更改其值。它在Internet Explorer 6-10中不受支持,但在Internet Explorer 11中包含。const关键字当前在函数范围内声明常量(如用var声明的变量)。

然后继续说:

const将由ECMAScript 6定义,但具有不同的语义。与用let语句声明的变量相似,用const声明的常量将是块作用域的。

如果您确实使用过const,则必须添加变通办法以支持稍旧的浏览器。


6
很好的答案-尽管我已经阅读了有关MDN的文章。如我所说,我对V8是否真的将const与var区别对待更感兴趣。我认为@Tibos清除了该问题。
axdg 2014年

詹姆斯感谢您指出支持方面。恕我直言,所有的javascript答案都应包含浏览器支持分类。很好的解释
Hubson Bropa 2015年

4
注意ES6已于2014年8月获得功能冻结。2015年7月,该标准正式发布。如果您现在正在阅读此书,则意味着如果您的代码是由最新引擎管理的,则应遵循列出的可接受答案。
FilipDupanović2015年

OP问题特定
Nicu Surdu '17

@NicolaeSurdu当然。它也是从2014年1月开始的,所以现在在2017
James Donnelly

41

对于为什么使用const,@Tibos的答案很棒。

但是你说:

据我所知,它用于创建不可变变量

那是错的。变异变量与重新分配变量不同:

var hello = 'world' // assigning
hello = 'bonjour!' // reassigning

使用const,您不能这样做:

const hello = 'world'
hello = 'bonjour!' // error

但是您可以更改变量:

const marks = [92, 83]
marks.push(95)
console.log(marks) // [92, 83, 95] -> the variable has been mutated.

因此,任何在使用=符号的情况下更改变量值的过程都会使变量变异。

注意:+=例如...正在重新分配!

var a = 5
a += 2 // is the same as a = a + 2

因此,最重要的是:const不会阻止您对变量进行变异,而是会阻止您重新分配变量。


4
您的说法“任何在使用=符号的情况下更改变量值的过程都是静音”,这在技术上是错误的。例如,const marks=[92,83]; marks[2]=95; console.log(marks)将输出[92, 83, 95]marks已通过等号突变。
切尔维'17

5
“但是你说:<<据我所知,它是用来创建不可变变量的。>>这是错误的。变量的可变与重新分配是不同的。”不,不是。重新分配正在使变量变异。您正在谈论使变量中引用的对象发生突变。完全是另一回事。
TJ Crowder

进入这里是因为我试图const在数组的上下文中进行理解(类似于@chharvey所使用的示例)。在的情况下const countArray = countup(n - 1); countArray.push(n);const是,在每次重新分配。那么,为什么使用const和不var
YCode

1
@YCode号 当您使用时const countArray,它将永远不会被重新分配。您仍然可以推送到数组,这会更改其成员和长度,但是我们不称其为重新分配。您可以使用const代替letvar当您想防止重新分配时使用。顺便说一句,如果您确实希望允许重新分配,那let总是比更好var
chharvey

@chharvey谢谢!您的回答使我想到了“价值传递vs引用传递”,一个新概念以及一个奇怪的概念,即价值修改≠重新分配。任何需要进一步说明的人都应在此处检查答案:stackoverflow.com/q/46131828/5965865
YCode

38

要集成先前的答案,除了性能原因外,在声明常量变量方面还有一个明显的优势:如果您不小心尝试在代码中更改或重新声明它们,则程序将不会分别更改值或引发错误。

例如,比较:

// Will output 'SECRET'

const x = 'SECRET'
if (x = 'ANOTHER_SECRET') {  // Warning! assigning a value variable in an if condition
    console.log (x)
}

与:

// Will output 'ANOTHER_SECRET'

var y = 'SECRET'
if (y = 'ANOTHER_SECRET') { 
    console.log (y)
}

要么

// Will throw TypeError: const 'x' has already been declared

const x = "SECRET"

/*  complex code */

var x = 0

// Will reassign y and cause trouble

var y = "SECRET"

/*  complex code */

var y = 0

您应该说这种“不可变的”行为仅适用于字符串,基本类型。使用对象,数组等,可以更改值,但无法重新分配新的“对象”,例如const a = [“ a”,“ b”];a = []; 会抛出错误,否则可能会发生
Fer To'Feb

您应该有一个尝试更改常量值的示例。
Joshua Pinter

使用const非常类似于访问修饰符,真正的不变性不是目标。
StingyJack

32

const不是一成不变的。

MDN

const声明创建对值的只读引用。这并不意味着它拥有的值是不可变的,只是不能重新分配变量标识符。


24
但是,这有点误导。对于数字,字符串,布尔值等(基元)const是不可变的。对于对象和数组,不能重新分配它,但是可以更改内容(例如array.push)。
Florian Wendelborn

2
JS原语始终是不可变的。无论您是否使用const,都不会影响它。
18Me21年

1
@Dodekeract因此,根据定义,它不是不变的。如果值可以更改,则它不是不变的,尽管它对于您列出的基元起着不变的作用
Anthony

13

var:声明一个变量,值初始化为可选。

let:声明一个具有块范围的局部变量。

const:声明一个只读的命名常量。

例如:

var a;
a = 1;
a = 2;//re-initialize possible
var a = 3;//re-declare
console.log(a);//3

let b;
b = 5;
b = 6;//re-initiliaze possible
// let b = 7; //re-declare not possible
console.log(b);

// const c;
// c = 9;   //initialization and declaration at same place
const c = 9;
// const c = 9;// re-declare and initialization is not possible
console.log(c);//9
// NOTE: Constants can be declared with uppercase or lowercase, but a common
// convention is to use all-uppercase letters.

10

您有很好的答案,但让我们保持简单。

const 当您有一个已定义的常量时,应使用(读为:在程序执行期间它不会更改)。

例如:

const pi = 3.1415926535

如果您认为以后可能会更改它,请使用var

根据示例,实际的区别在于,const您总是会假设pi为3.14 [...],这是事实。

如果将其定义为var,则可能不是3.14 [...]。

对于更多的技术答案,@ Tibos在学术上是正确的。


7

以我的经验,当我想要设置某些内容时,我可以使用const,而以后无需浏览代码即可查找经过硬编码的位,例如文件路径或服务器名称。

测试中的错误是另一回事,您正在尝试制作另一个名为x的变量,这将是一个更准确的测试。

const x = 'const';
x = 'not-const';

9
我明白您的意思,但是-有趣的是,“常数”对您来说意味着“我可能想改变的东西”。:P
Venryx

4

个人喜好。如您所说,可以在不重新分配常量且常量的情况下使用const。例如,如果您想分配生日。您的生日永远不会改变,因此您可以将其用作常量。但是您的年龄确实发生了变化,因此可能会有所不同。


17
那将是一个运行时间很长的脚本!
nullability

3
@nullability取决于您要跟踪的年龄。几十个脚本就不需要花很长时间了:)。
米莉·史密斯

4

摘要:

const创建一个不可变的绑定,这意味着const变量标识符不可重新分配。

const a = "value1";

您不能通过以下方式重新分配它

a = "value2";

但是,如果const标识符包含一个对象或数组,则只要我们不重新分配它,就可以更改其值。

const x = { a: 1 }

x.a = 2; //is possible and allowed

const numbers = [1, 2];
numbers.push(3); //is possible and allowed

请注意,const是一个块级作用域,就像let一样, 它与var(它是函数作用域)不同

简而言之,当某些事情不太可能通过重新分配更改时,请使用const,否则根据您希望的范围使用letvar

当代码死了很明显时,通过重新分配可以更改哪些内容以及不能更改哪些内容,就可以更容易地对代码进行推理。将const更改为let非常简单。默认情况下使用const会使您在进行此操作之前三思而后行。在许多情况下,这是一件好事。



2
Main point is that how to decide which one identifier should be used during development.
In java-script here are three identifiers.

1. var (Can re-declared & re-initialize)
2. const (Can't re-declared & re-initialize, can update array values by using push)
3. let (Can re-initialize but can't re-declare)

'var':在编写代码标准时,我们通常使用标识符的名称,其他用户/开发人员很容易理解该标识符的名称。例如,如果我们正在考虑使用许多函数,其中使用一些输入并对其进行处理并返回一些结果,例如:

**Example of variable use**

function firstFunction(input1,input2)
{
 var process = input1 + 2; 
 var result = process - input2;
 return result;
}


function otherFunction(input1,input2)
{
 var process = input1 + 8; 
 var result = process * input2;
 return result;
}

在上面的示例中,两个函数产生不同的2结果,但使用相同的变量名。在这里,我们可以看到'process'和'result'都被用作变量,应该使用。

 **Example of constant with variable**

 const tax = 10; 
 const pi = 3.1415926535; 

function firstFunction(input1,input2)
{
 var process = input1 + 2; 
 var result = process - input2;
 result = (result * tax)/100; 
 return result;
}


function otherFunction(input1,input2)
{
 var process = input1 + 8; 
 var result = process * input2 * pi;
 return result;
}

在Java脚本中使用“让”之前,我们必须在js文件顶部添加“使用严格”

 **Example of let with constant & variable**

 const tax = 10; 
 const pi = 3.1415926535; 
 let trackExecution = '';

function firstFunction(input1,input2)
{
 trackExecution += 'On firstFunction'; 
 var process = input1 + 2; 
 var result = process - input2;
 result = (result * tax)/100; 
 return result;
}


function otherFunction(input1,input2)
{
 trackExecution += 'On otherFunction'; # can add current time 
 var process = input1 + 8; 
 var result = process * input2 * pi;
 return result;
}

 firstFunction();
 otherFunction();
 console.log(trackExecution);

在上面的示例中,您可以跟踪在特定操作期间何时使用哪个功能以及何时不使用哪个功能。


1

首先,三点有用的事情const(除了与之共享的范围改进之外let):

  • 它为以后阅读代码的人提供了证明,该值不得更改。
  • 它可以防止您(或任何追随您的人)更改值,除非他们回去有意更改声明。
  • 可以为JavaScript引擎节省一些优化方面的分析。例如,您已经声明该值不能更改,因此引擎不必做任何工作来确定该值是否更改,因此它可以根据未更改的值来决定是否进行优化。

你的问题:

什么时候可以const代替var

可以做任何你声明一个变量,其值永远不会改变的时间。您是否认为合适完全取决于您的偏好/团队的偏好。

是否应该在每次声明一个不会被重新分配的变量时使用它?

这取决于您/您的团队。

如果var is used in place ofconst`或反之,实际上有什么区别吗?

是:

  • varconst具有不同的范围规则。(您可能想与let而不是进行比较var。)特别是:const并且let它们是块范围的,并且在全局范围内使用时,不要在全局对象上创建属性(即使它们确实创建了全局变量)。var具有全局范围(在全局范围内使用时)或函数范围(即使在块中使用),并且在全局范围内使用时,会在全局对象上创建属性。
  • 参见上面的“三件事”,它们都适用于此问题。

1

的语义varlet

var并向let机器和其他程序员声明:

我打算在执行过程中更改此赋值。不要依赖此分配的最终值。

使用var和的含义let

varlet迫使其他程序员读取从声明到最终使用的所有中间代码,并在程序执行的那一刻说明赋值的原因。

它们削弱了ESLint和其他语言服务的机器推理能力,从而无法在以后的分配中正确检测到类型错误的变量名,并且在内部作用域忘记声明的情况下重新使用外部作用域变量名的作用域。

它们还使运行时在所有代码路径上运行许多迭代,以在对其进行优化之前检测到它们实际上实际上是常量。尽管这比漏洞检测和开发人员易理解性要小。

何时使用 const

如果引用的值在执行过程中没有变化,则表示程序员意图的正确语法为const。对于对象,更改引用的值意味着指向另一个对象,因为引用是不可变的,但对象不是。

const”对象

对于对象引用,不能将指针更改为另一个对象,但是创建并分配给const声明的对象可变的。您可以在const引用的数组中添加或删除项目,并对const引用的对象更改属性键。

要实现不可变的对象(这又使代码易于为人和机器推理),可以Object.freeze在声明/分配/创建处使用该对象,如下所示:

const Options = Object.freeze(['YES', 'NO'])

Object.freeze确实会影响性能,但是由于其他原因,您的代码可能会变慢。您要配置它。

您还可以将可变对象封装在状态机中,并将深层副本作为值返回(这是Redux和React状态的工作方式)。有关如何根据基本原理构建此状态的示例,请参见在Browser JS中避免使用可变的全局状态

什么时候varlet很好的搭配

letvar代表可变状态。在我看来,它们应仅用于模拟实际可变状态。诸如“ 连接是否还存在? ”之类的信息。

最好将它们封装在可测试的状态机中,这些状态机公开表示“ 连接的当前状态常量值,该常量在任何时间点都是常量,而其余代码实际上是您感兴趣的。

编写副作用和转换数据已经足够困难。通过创建带有变量的可变状态,将每个功能变成不可测试的状态机,只会增加复杂性。

有关更细微的解释,请参见《突变的信徒-案例》const



0

我不是JS编译行业的专家,但是可以说,v8是在const标志中使用的

通常,在声明并更改了一堆变量之后,内存会碎片化,并且v8停止执行,暂停几秒钟,以进行gc或垃圾回收。

如果使用const v8声明了变量,则可以放心将其放在其他const变量之间的固定大小固定容器中,因为它永远不会改变。由于类型不会更改,因此它还可以保存该数据类型的正确操作。


0

对于letconst之间的决定,请始终首选const,以便代码中清楚使用。这样,如果您尝试重新声明该变量,则会收到错误消息。如果没有别的选择,只能重新声明,那就换为let。请注意,正如Anthony所说,这些值并非一成不变的(例如,一个const对象可以使属性发生突变)。

关于var,由于ES6已经发布,所以我从未在生产代码中使用过它,也没有想到它的用例。但是,请注意,用var声明的变量没有块范围。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.