JavaScript中的Const:什么时候使用它,它是必要的?

我最近在JavaScript中遇到了< >强const < / >强关键字。据我所知,它是用来创建< em > < / em >不变的变量的,我已经测试了,以确保它不能被重新定义(在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或反之亦然?李< / >
233145 次浏览

个人喜好。你可以使用const,就像你说的,它不会被重新赋值并且是常量。例如,如果你想分配你的生日。你的生日永远不变,所以你可以把它作为一个常数。但你的年龄确实在变化,所以这可能是一个变量。

根据我的经验,当我想设置一些我以后可能想更改的东西时,我使用常量,而不必遍历代码寻找已经硬编码的位,例如,文件路径或服务器名称。

测试中的错误是另一回事。你试图创建另一个名为x的变量,这将是一个更准确的测试:

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

2017年更新

这个答案仍然受到很多关注。值得注意的是,这个答案是在2014年初发布的,从那时起发生了很多变化。支持现在是标准。所有现代浏览器现在支持const,所以使用它应该是非常安全的,没有任何问题。


2014年原创答案

尽管有相当不错的浏览器支持,但我现在会避免使用它。从MDN关于const的文章:

const的当前实现是mozilla特定的扩展,不是ECMAScript 5的一部分。Firefox &铬(V8)。从Safari 5.1.7和Opera 12.00开始,如果在这些浏览器中使用const定义变量,以后仍然可以更改它的值。Internet Explorer 6-10不支持,但Internet Explorer 11支持。const关键字当前在函数作用域中声明常量(就像用var声明变量一样)。

它接着说:

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

如果你确实使用const,你将不得不添加一个变通方法来支持稍微老一点的浏览器。

你的问题有两个方面:使用const而不是var的技术方面是什么,以及这样做与人有关的方面是什么。

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

与人相关的方面是关键字的语义。变量是一种数据结构,其中包含预期会发生变化的信息。常量是一种包含永远不会改变的信息的数据结构。如果存在错误的空间,则应该始终使用var。然而,并非所有在程序生命周期中永不改变的信息都需要用const声明。如果在不同的情况下信息应该改变,使用var来表示,即使实际的改变没有出现在你的代码中。

你回答得很好,但还是简单点吧。

const应该在你有一个定义的常量时使用(读作:它在你的程序执行期间不会改变)。

例如:

const pi = 3.1415926535

如果你认为它可能在以后的执行中被改变,那么使用var

根据这个例子,实际的区别是,使用const时,你总是假设pi将是3.14[…],这是事实。

如果你将它定义为var,它可能是3.14[…]或者不是。

对于一个更专业的答案,提伯”在学术上是正确的。

为了整合前面的答案,除了性能原因外,声明常量变量有一个明显的优势:如果您意外地试图在代码中更改或重新声明它们,程序将分别不更改值或抛出错误。

例如,比较:

// 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

它提供了:

  1. 一个常量引用,例如,const x = []——数组可以被修改,但x不能指向另一个数组;而且

  2. < p >块范围。

constlet将一起替换ECMAScript 6/2015中的var。参见JavaScript ES6变量声明与let和const中的讨论

const不可变的。

中数:

const声明创建一个对某个值的只读引用。它 这并不意味着它持有的值是不可变的,只是变量

.标识符不能被重新分配

'const'指示您的代码标识符将不会被重新分配。

这是一篇关于何时使用'const', 'let'或'var'的好文章:JavaScript ES6+: var, let, or const?< / >

对于为什么使用const提伯回答的很棒。

但是你说:

据我所知,它是用来创建不可变变量的

这是错误的。改变变量不同于重新赋值:

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不阻止你使用变异变量;它阻止你重新分配它们。

首先,关于const有三个有用的东西(除了它与let共享的作用域改进之外):

  • 它为以后阅读代码的人记录了该值不能更改。
  • 它可以防止您(或任何跟随您的人)更改值,除非他们返回并有意更改声明。
  • 它在优化方面为JavaScript引擎节省了一些分析。例如,你已经声明了值不能改变,所以引擎不需要做功来确定值是否改变,所以它可以决定是否基于值不变进行优化。

你的问题:

什么时候用const代替var比较合适?

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

每次声明一个不会被重新赋值的变量时都应该使用它吗?

这取决于你/你的团队。

如果var is used in place ofconst '或反之,是否有任何区别?

是的:

  • varconst有不同的作用域规则。(你可能想与let而不是var进行比较。)具体来说:constlet是块作用域的,当在全局作用域使用时,不会在全局对象上创建属性(即使它们创建全局对象)。var具有全局作用域(在全局作用域中使用时)或函数作用域(即使在块中使用时),并且在全局作用域中使用时,在全局对象上创建一个属性。
  • 看看我上面提到的“三件有用的事情”,它们都适用于这个问题。

我不是JavaScript编译方面的专家,但是可以这么说,V8使用了const标志。

通常在声明和改变一堆变量后,内存会被分割,V8会停止执行,暂停几秒钟,进行垃圾收集,或者垃圾收集。

如果一个变量是用常量声明的,V8就可以放心地把它放在一个紧密固定大小的容器中,放在其他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

请注意,常量是一个block-scoped,就像一样,它与var(函数作用域)不同。

简而言之,当某些东西不太可能通过重新分配来改变使用常量时,否则使用var,这取决于你想要的作用域。

当可以通过重赋改变什么,不能通过重赋改变什么的时候,对代码进行推理就容易得多了。将常量更改为非常简单。并且默认使用常量会让你在这样做之前三思。在很多情况下,这是一件好事。

var:声明变量。值初始化是可选的。

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

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

例子:

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


let b;
b = 5;
b = 6; // Reinitialise possible
// let b = 7; // Redeclare not possible
console.log(b);


// const c;
// c = 9;    // Initialization and declaration at the same place
const c = 9;
// const c = 9; // Redeclare 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.

重点在于如何决定在开发过程中应该使用哪一个标识符。

在JavaScript中有三个标识符。

  1. var(可以重新声明和重新初始化)
  2. const(不能重新声明和重新初始化,可以使用push更新数组值)
  3. Let(可以重新初始化,但不能重新声明)

'var':在编码时,当我们谈论代码标准时,我们通常使用易于其他用户和开发人员理解的标识符的名称。

例如,如果我们正在考虑使用一些输入并处理它并返回一些结果的许多函数,例如:

变量使用的例子

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'都被用作变量,它们应该是。

常数与变量的例子

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;
}

在JavaScript中使用“let”之前,我们必须在JavaScript文件顶部添加“use strict”

let与常量&的例子;变量

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);

在上面的例子中,你可以跟踪哪个函数在&在特定的动作中,哪个函数没有被使用。

varlet的语义

varlet是对机器和其他程序员的语句:

我希望这个赋值在执行过程中发生变化。不要依赖于这个赋值的最终值。

使用varlet的含义

varlet迫使其他程序员读取从声明到最终使用的所有中间代码,并在程序执行的这一点上推理赋值。

它们削弱了ESLint和其他语言服务的机器推理,从而在以后的赋值中正确检测输入错误的变量名,并在内部作用域忘记声明的情况下对外部作用域变量名进行作用域重用。

它们还导致运行时在所有代码路径上运行多次迭代,以检测它们实际上是常量,然后才能优化它们。尽管这比错误检测和开发人员可理解性的问题要小。

何时使用const

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

const”对象

对于对象引用,指针不能更改为另一个对象,但创建并赋值给const声明的对象 mutable。您可以从const引用的数组中添加或删除项,并更改const引用对象的属性键。

为了实现不可变对象(这同样使你的代码更容易为人类和机器推理),你可以在声明/赋值/创建时Object.freeze对象,像这样:

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

freeze确实对性能有影响,但您的代码可能因为其他原因而变慢。你想要侧写它。

你也可以将可变对象封装在状态机中,并返回深度副本作为值(这就是Redux和React状态的工作方式)。参见避免浏览器JS中的可变全局状态以获得如何从基本原理构建它的示例。

varlet是一个很好的匹配

letvar表示可变状态。在我看来,它们应该只用于建模实际可变状态。比如"连接是否正常?"。

这些最好封装在可测试状态机中,这些状态机公开了表示“连接的当前状态”的常量值,这在任何时间点都是常量,以及您的其余代码实际感兴趣的内容。

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

有关更微妙的解释,请参见避开变种人——const的情况

当涉及到常量(都是块作用域)之间的决定时,总是倾向于常量,以便在代码中使用清楚。这样,如果您试图重新声明变量,就会得到一个错误。如果没有其他选择,只能重新声明它,只需切换为。注意,正如安东尼所说,常量值不是不可变的(例如,常量对象的属性可以发生变化)。

当谈到var时,因为ES6出来了,我从来没有在生产代码中使用过它,也想不出它的用例。可以考虑使用它的一个点是JavaScript起重——虽然常量没有被提升,但var声明被提升。然而,要注意用var声明的变量只有函数作用域,而不是块作用域(«如果在任何函数之外声明,它们将在整个程序中全局可用;如果在函数中声明,它们只在函数本身»中可用,在HackerRank -变量声明关键字)。你可以把看作是var的块作用域版本。

我的意见:

< p >。什么时候用const代替var比较合适?
答:从来没有!< / p >

Q:每次声明一个不会被重新赋值的变量时都应该使用它吗?
答:从来没有!就像这将减少资源消耗…

< p >。如果使用var来代替const,或者反之亦然,这实际上有什么区别吗?
答:是的!使用var才是正确的方法!更容易在开发工具和节省创建一个新的文件进行测试。(var in not in place of const - const is trying to take var's place…)

额外的A:同样适用于let。JavaScript是一种松散的语言——为什么要constrict它?!?