何时在Java语言中使用var,let和const [Tyler McGinnis文章翻译]

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

图片

在本文中,您将学习在Javascript(ES6)中创建变量let和const的2种新方法。 在整个本文中,我们将研究varletconst之间的区别,以及相关主题,例如:“函数作用域与块作用域”,“提高”变量和抗扰度。

如果您喜欢视频,请观看以下视频(英文原版):


ES2015(或ES6)向我们介绍了创建变量letconst的 2种新方法。 但是在深入研究varletconst之间的区别之前,您需要首先了解一些主题。 这些是变量的声明及其初始化,范围(函数的特殊范围)和“ raising”。

声明和初始化变量


变量声明引入了新的标识符。

var declaration 

在上方,我们创建了一个新的标识符,我们将其命名为“ declaration”。 在Javascript中,创建后,变量会使用未定义的值进行初始化。 这意味着,如果我们尝试输出声明变量,则会得到undefined

 var declaration console.log(declaration) 

因此,我们推断了声明变量,但未定义

与声明变量相比,初始化变量是您第一次设置此变量的值。

 var declaration console.log(declaration) // undefined declaration = '  ' 

因此,这里我们通过向其写入字符串来初始化声明变量。

这就引出了下一个概念,范围。

适用范围


范围描述了可以在程序中访问变量和函数的位置。 在Javascript中,作用域有2种类型- 全局作用域函数作用域 。 根据官方规范,
“如果变量声明出现在函数声明内,则该变量在此函数的本地范围内定义...”
这意味着,如果使用var创建变量,则此变量的作用域将是创建该变量的函数,并且仅在该函数或任何其他嵌套函数内部可用。

 function getDate () { var date = new Date() return date } getDate() console.log(date) // NOT OK: Reference Error 

上面,我们尝试从声明该变量的函数外部访问该变量。 由于date变量的范围是getDate函数,因此仅在该函数内部或嵌套在getDate中的任何其他函数中可用(如下所示)。

 function getDate () { var date = new Date() function formatDate () { return date.toDateString().slice(4) // OK } return formatDate() } getDate() console.log(date) // NOT OK: Reference Error 

现在,让我们看一个更高级的示例。 假设我们有一个价格数组,我们需要一个函数,该函数接受此数组以及折扣变量,并向我们返回带有折扣的新价格数组。 最终目标可能如下所示:

 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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } 

如果JavaScript是您所知道的唯一编程语言,则不必担心那么多。 但是,如果您是从另一种编程语言(特别是阻止范围的编程语言)来学习JavaScript的,那么您可能会担心这里发生的事情。

它没有坏,只是有点奇怪。 确实没有必要for循环之外访问iDiscountPricefinalPrice 。 它对我们没有任何好处,甚至可能在某些情况下伤害我们。 但是,由于变量是使用var声明的,因此它们属于函数的范围,您可以访问它们。

现在,我们讨论了变量的声明和初始化以及范围,这是我们在深入研究letconst之间的区别之前需要处理的另一件事,这就是“提高”。

“举升”


请记住,以前曾说过:“在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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } 

请注意,所有声明的变量都已设置为undefined 。 这就是为什么如果您在实际宣布其中之一之前尝试访问其中之一,则只会得到undefined

 function discountPrices (prices, discount) { console.log(discounted) // undefined 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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } 

现在,您了解了有关var的所有信息,现在让我们最后讨论一下我们的主要目标: varletconst有什么区别?

var,let或const


首先,让我们比较varletvarlet之间的主要区别在于,除了全局范围和函数范围之外,还可以在块范围内定义变量。 这意味着使用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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } 

回想一下,我们有权在for循环外输出iDiscountPricefinalPrice ,因为它们是使用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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } discountPrices([100, 200, 300], .5) // NOT OK: ReferenceError: i is not defined 

我们得到ReferenceError:我没有定义 。 这告诉我们用let声明的变量仅限于块的范围,而不是函数的范围。 尝试在声明它们的“块”之外调用i (或DiscountedPricefinalPrice ),这将给我们带来调用错误,如我们所见。

 var VS let var:     let:     

以下差异与“隆起”有关。 我们之前说过,“ uplift”的定义是:“ JavaScript解释器在称为“ Creation”的阶段将声明的变量设置为undefined 。”我们还通过在声明变量之前调用变量(您得到了undefined )看到了这一点。

 function discountPrices (prices, discount) { console.log(discounted) // undefined 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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return discounted } 

当您确实想在声明变量之前访问变量时,我无法回忆起一个用例。 似乎获得ReferenceError比获得undefined更好。

实际上,这就是let所做的。 如果您尝试在使用let声明变量之前访问变量,而不是获取未定义的变量(如使用var声明变量那样),则将获得ReferenceError

 function discountPrices (prices, discount) { console.log(discounted) // NOT OK: ReferenceError 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) // 3 console.log(discountedPrice) // 150 console.log(finalPrice) // 150 return 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' // OK handle = '@tylermcginnis' // NOT OK: TypeError: Assignment to constant variable. 

上面的结论是,用let声明的变量可以被覆盖,用const声明的变量不能被覆盖。

太好了,既然您希望变量是不可变的,则可以使用const声明它。 还是不是。 仅仅因为使用const声明了一个变量并不意味着它是不可变的,所以这意味着它不能被覆盖。 下面是一个很好的例子。

 const person = { name: 'Kim Kardashian' } person.name = 'Kim Kardashian West' // OK person = {} // NOT OK: Assignment to constant variable. 

请注意,更改对象的属性不是覆盖,因此即使使用const声明了该对象,也不意味着您不能更改其任何属性。 这仅意味着您不能覆盖该对象。

现在,尚未回答的最重要的问题:我应该使用varlet还是const ? 我坚持的最流行的观点是,始终使用const,直到您知道变量是否会更改。 这样做的原因是,使用const可以使您自己以及将来的开发人员(应阅读您的代码)都清楚不要更改此变量。 如果需要更改(例如在for循环中),只需使用let即可

变化的变量与不变的变量之间没有多少情况。 这意味着您将不再需要再次使用var

现在,尽管仍然有道理,但不受欢迎的观点是,您不应该使用const ,尽管您正试图证明此变量是不可变的,正如我们在上面看到的那样,这并不完全正确。 持有这种观点的开发人员只要没有实际为常量的变量(例如_LOCATION_ = ...)就始终使用let。

让我们对以上内容进行总结, var受函数范围的限制,如果您在声明变量之前尝试访问此类变量,则会得到undefinedconstlet受块范围的限制,如果在声明它们之前尝试访问这些变量,则会得到ReferenceErrorconstlet之间的区别在于,与let不同,不能覆盖分配给const的值。

 var VS let VS const var:        undefined         . let:       ReferenceError        . const:       ReferenceError        .     

本文最初在tylermcginnis.com上发布,是Modern JavaScript课程的一部分。

感谢您阅读此翻译,希望您遇到了对自己有用的新知识。 我很高兴看到反馈!

Source: https://habr.com/ru/post/zh-CN438880/


All Articles