哈Ha! 我向您介绍泰勒·麦金尼斯(Tyler McGinnis)撰写的文章
“ JavaScript中的var vs let vs const” 。

在本文中,您将学习在Javascript(ES6)中创建变量let和const的2种新方法。 在整个本文中,我们将研究
var ,
let和
const之间的区别,以及相关主题,例如:“函数作用域与块作用域”,“提高”变量和抗扰度。
如果您喜欢视频,请观看以下视频(英文原版):
ES2015(或ES6)向我们介绍了创建变量
let和
const的 2种新方法。 但是在深入研究
var ,
let和
const之间的区别之前,您需要首先了解一些主题。 这些是变量的声明及其初始化,范围(函数的特殊范围)和“ raising”。
声明和初始化变量
变量声明引入了新的标识符。
var declaration
在上方,我们创建了一个新的标识符,我们将其命名为“ declaration”。 在Javascript中,创建后,变量会使用
未定义的值进行初始化。 这意味着,如果我们尝试输出
声明变量,则会得到
undefined 。
var declaration console.log(declaration)
因此,我们推断了
声明变量,但
未定义 。
与声明变量相比,初始化变量是您第一次设置此变量的值。
var declaration console.log(declaration)
因此,这里我们通过向其写入字符串来初始化
声明变量。
这就引出了下一个概念,范围。
适用范围
范围描述了可以在程序中访问变量和函数的位置。 在Javascript中,作用域有2种类型- 全局作用域和函数作用域 。 根据官方规范,
“如果变量声明出现在函数声明内,则该变量在此函数的本地范围内定义...”
这意味着,如果使用var创建变量,则此变量的作用域将是创建该变量的函数,并且仅在该函数或任何其他嵌套函数内部可用。
function getDate () { var date = new Date() return date } getDate() console.log(date)
上面,我们尝试从声明该变量的函数外部访问该变量。 由于date变量的范围是getDate函数,因此仅在该函数内部或嵌套在getDate中的任何其他函数中可用(如下所示)。
function getDate () { var date = new Date() function formatDate () { return date.toDateString().slice(4)
现在,让我们看一个更高级的示例。 假设我们有一个价格数组,我们需要一个函数,该函数接受此数组以及折扣变量,并向我们返回带有折扣的新价格数组。 最终目标可能如下所示:
discountPrices([100, 200, 300], .5)
实现可能看起来像这样:
function discountPrices (prices, discount) { var discounted = [] for (var i = 0; i < prices.length; i++) { var discountedPrice = prices[i] * (1 - discount) var finalPrice = Math.round(discountedPrice * 100) / 100 discounted.push(finalPrice) } return discounted }
它看起来很简单,但这与块的范围有什么关系? 看看这个for循环。 在其内部声明的变量可以在其外部访问吗? 原来可用。
function discountPrices (prices, discount) { var discounted = [] for (var i = 0; i < prices.length; i++) { var discountedPrice = prices[i] * (1 - discount) var finalPrice = Math.round(discountedPrice * 100) / 100 discounted.push(finalPrice) } console.log(i)
如果JavaScript是您所知道的唯一编程语言,则不必担心那么多。 但是,如果您是从另一种编程语言(特别是阻止范围的编程语言)来学习JavaScript的,那么您可能会担心这里发生的事情。
它没有坏,只是有点奇怪。 确实没有必要在for循环之外访问i , DiscountPrice和finalPrice 。 它对我们没有任何好处,甚至可能在某些情况下伤害我们。 但是,由于变量是使用var声明的,因此它们属于函数的范围,您可以访问它们。
现在,我们讨论了变量的声明和初始化以及范围,这是我们在深入研究let和const之间的区别之前需要处理的另一件事,这就是“提高”。
“举升”
请记住,以前曾说过:“在Javascript中,创建时,变量会使用未定义的值进行初始化”。 事实证明,这意味着“提升”。 JavaScript解释器在称为“创建”的阶段将声明的变量设置为undefined 。
有关创建阶段“提升”和范围的更详细的研究,请阅读本文: “ JavaScript中的提升,范围和闭包的终极指南” 。
让我们看一下前面的示例,看看“隆起”如何影响它。
function discountPrices (prices, discount) { var discounted = undefined var i = undefined var discountedPrice = undefined var finalPrice = undefined discounted = [] for (var i = 0; i < prices.length; i++) { discountedPrice = prices[i] * (1 - discount) finalPrice = Math.round(discountedPrice * 100) / 100 discounted.push(finalPrice) } console.log(i)
请注意,所有声明的变量都已设置为undefined 。 这就是为什么如果您在实际宣布其中之一之前尝试访问其中之一,则只会得到undefined 。
function discountPrices (prices, discount) { console.log(discounted)
现在,您了解了有关var的所有信息,现在让我们最后讨论一下我们的主要目标: var , let和const有什么区别?
var,let或const
首先,让我们比较var和let 。 var和let之间的主要区别在于,除了全局范围和函数范围之外,还可以在块范围内定义变量。 这意味着使用let关键字创建的变量在创建它的“块”内部以及嵌套块中可用。 当我说“ block”时,是指用花括号{}括起来的内容,例如for循环或if语句 。
因此,让我们最后一次回到我们的DiscountPrices函数。
function discountPrices (prices, discount) { var discounted = [] for (var i = 0; i < prices.length; i++) { var discountedPrice = prices[i] * (1 - discount) var finalPrice = Math.round(discountedPrice * 100) / 100 discounted.push(finalPrice) } console.log(i)
回想一下,我们有权在for循环外输出i , DiscountPrice和finalPrice ,因为它们是使用var声明的,并且使用var关键字声明的变量仅限于函数的范围。 但是,如果我们将var更改为let并尝试运行我们的代码,现在会发生什么?
function discountPrices (prices, discount) { let discounted = [] for (let i = 0; i < prices.length; i++) { let discountedPrice = prices[i] * (1 - discount) let finalPrice = Math.round(discountedPrice * 100) / 100 discounted.push(finalPrice) } console.log(i)
我们得到ReferenceError:我没有定义 。 这告诉我们用let声明的变量仅限于块的范围,而不是函数的范围。 尝试在声明它们的“块”之外调用i (或DiscountedPrice或finalPrice ),这将给我们带来调用错误,如我们所见。
var VS let var: let:
以下差异与“隆起”有关。 我们之前说过,“ uplift”的定义是:“ JavaScript解释器在称为“ Creation”的阶段将声明的变量设置为undefined 。”我们还通过在声明变量之前调用变量(您得到了undefined )看到了这一点。
function discountPrices (prices, discount) { console.log(discounted)
当您确实想在声明变量之前访问变量时,我无法回忆起一个用例。 似乎获得ReferenceError比获得undefined更好。
实际上,这就是let所做的。 如果您尝试在使用let声明变量之前访问变量,而不是获取未定义的变量(如使用var声明变量那样),则将获得ReferenceError 。
function discountPrices (prices, discount) { console.log(discounted)
var VS let var: undefined . let: ReferenceError .
let或const
现在您了解了var和let之间的区别,那么const呢? 事实证明const与let几乎相同。 但是,有一个区别:如果曾经使用const分配了一个值,则无法将其更改为另一个。
let name = 'Tyler' const handle = 'tylermcginnis' name = 'Tyler McGinnis'
上面的结论是,用let声明的变量可以被覆盖,用const声明的变量不能被覆盖。
太好了,既然您希望变量是不可变的,则可以使用const声明它。 还是不是。 仅仅因为使用const声明了一个变量并不意味着它是不可变的,所以这意味着它不能被覆盖。 下面是一个很好的例子。
const person = { name: 'Kim Kardashian' } person.name = 'Kim Kardashian West'
请注意,更改对象的属性不是覆盖,因此即使使用const声明了该对象,也不意味着您不能更改其任何属性。 这仅意味着您不能覆盖该对象。
现在,尚未回答的最重要的问题:我应该使用var , let还是const ? 我坚持的最流行的观点是,始终使用const,直到您知道变量是否会更改。 这样做的原因是,使用const可以使您自己以及将来的开发人员(应阅读您的代码)都清楚不要更改此变量。 如果需要更改(例如在for循环中),只需使用let即可 。
变化的变量与不变的变量之间没有多少情况。 这意味着您将不再需要再次使用var 。
现在,尽管仍然有道理,但不受欢迎的观点是,您不应该使用const ,尽管您正试图证明此变量是不可变的,正如我们在上面看到的那样,这并不完全正确。 持有这种观点的开发人员只要没有实际为常量的变量(例如_LOCATION_ = ...)就始终使用let。
让我们对以上内容进行总结, var受函数范围的限制,如果您在声明变量之前尝试访问此类变量,则会得到undefined 。 const和let受块范围的限制,如果在声明它们之前尝试访问这些变量,则会得到ReferenceError 。 const和let之间的区别在于,与let不同,不能覆盖分配给const的值。
var VS let VS const var: undefined . let: ReferenceError . const: ReferenceError .
本文最初在tylermcginnis.com上发布,是Modern JavaScript课程的一部分。
感谢您阅读此翻译,希望您遇到了对自己有用的新知识。 我很高兴看到反馈!