本文共 15576 字,大约阅读时间需要 51 分钟。
In this post you'll learn two new ways to create variables in JavaScript (ES6), let
and const
. Along the way we'll look at the differences between var
, let
, and const
as well as cover topics like function vs block scope, variable hoisting, and immutability.
在本文中,您将学习let
和const
两种在JavaScript(ES6)中创建变量的新方法。 在此过程中,我们将研究var
, let
和const
之间的区别,并涵盖诸如函数与块作用域,变量提升和不变性之类的主题。
ES2015 (or ES6) introduced two new ways to create variables, let
and const
. But before we actually dive into the differences between var
, let
, and const
, there are some prerequisites you need to know first. They are variable declarations vs initialization, scope (specifically function scope), and hoisting.
ES2015(或ES6)引入了两种创建变量的新方法let
和const
。 但是,在我们实际研究var
, let
和const
之间的差异之前,您需要首先了解一些先决条件。 它们是变量声明与初始化,作用域(特别是函数作用域)和提升。
A variable declaration introduces a new identifier.
变量声明引入了新的标识符。
var declaration
Above we create a new identifier called declaration. In JavaScript, variables are initialized with the value of undefined
when they are created. What that means is if we try to log the declaration
variable, we'll get undefined
.
在上面,我们创建一个称为声明的新标识符。 在JavaScript中,变量在创建时会使用undefined
的值进行初始化。 这意味着如果我们尝试记录declaration
变量,则会得到undefined
。
var declarationconsole.log(declaration) // undefined
So if we log the declaration variable, we get undefined.
因此,如果我们记录声明变量,则会得到未定义。
In contract to variable declaration, variable initialization is when you first assign a value to a variable.
按照变量声明的约定,变量初始化是您首次为变量分配值时。
var declarationconsole.log(declaration) // undefineddeclaration = 'This is an initialization'
So here we're initializing the declaration
variable by assigning it to a string.
因此,这里我们通过将declaration
变量分配给字符串来初始化它。
This leads us to our second concept, Scope.
这就引出了我们的第二个概念,范围。
Scope defines where variables and functions are accessible inside of your program. In JavaScript, there are two kinds of scope - global scope, and function scope. According to the official spec,
范围定义了在程序内部可访问变量和函数的位置。 在JavaScript中,有两种作用域- 全局作用域和函数作用域 。 根据官方规范,
"If the variable statement occurs inside a FunctionDeclaration, the variables are defined with function-local scope in that function.".
“如果变量语句出现在FunctionDeclaration内部,则在该函数中使用局部函数作用域定义变量。”
What that means is if you create a variable with var
, that variable is "scoped" to the function it was created in and is only accessible inside of that function or, any nested functions.
这就是说,如果您使用var
创建变量,则该变量将“作用域”到创建该函数的函数,并且只能在该函数或任何嵌套函数内部访问。
function getDate () { var date = new Date() return date}getDate()console.log(date) // ❌ Reference Error
Above we try to access a variable outside of the function it was declared. Because date
is "scoped" to the getData
function, it's only accessible inside of getDate
itself or any nested functions inside of getDate
(as seen below).
上面我们尝试在声明的函数之外访问变量。 因为date
是“作用域”到getData
功能,它是唯一能够内部getDate
本身或内部的任何嵌套函数getDate
(如下图所示)。
function getDate () { var date = new Date() function formatDate () { return date.toDateString().slice(4) // ✅ } return formatDate()}getDate()console.log(date) // ❌ Reference Error
Now let's look at a more advanced example. Say we had an array of prices
and we needed a function that took in that array as well as a discount
and returned us a new array of discounted prices. The end goal might look something like this.
现在让我们看一个更高级的例子。 假设我们有一个prices
数组,我们需要一个函数,该函数接受该数组以及discount
,并为我们返回新的折扣价格数组。 最终目标可能看起来像这样。
discountPrices([100, 200, 300], .5) // [50, 100, 150]
And the implementation might look something like this
实现可能看起来像这样
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}
Seems simple enough but what does this have to do with block scope? Take a look at that for
loop. Are the variables declared inside of it accessible outside of it? Turns out, they are.
看起来很简单,但这与块作用域有什么关系? 看一下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}
If JavaScript is the only programming language you know, you may not think anything of this. However, if you're coming to JavaScript from another programming language, specifically a programming language that is blocked scope, you're probably a little bit concerned about what's going on here. It's not really broken, it's just kind of weird. There's not really a reason to still have access to i
, discountedPrice
, and finalPrice
outside of the for
loop. It doesn't really do us any good and it may even cause us harm in some cases. However, since variables declared with var
are function scoped, you do.
如果JavaScript是您所知道的唯一编程语言,那么您可能对此一无所知。 但是,如果您是从另一种编程语言(特别是受限制范围的编程语言)使用JavaScript的,那么您可能会有点担心这里发生的事情。 它并没有真正坏掉,只是有点奇怪。 确实没有理由仍然可以在for
循环之外访问i
, discountedPrice
和finalPrice
。 它实际上并没有给我们带来任何好处,在某些情况下甚至可能导致我们受到伤害。 但是,由于用var
声明的变量是函数作用域的,所以您可以这样做。
Now that we've discussed variable declarations, initializations, and scope, the last thing we need to flush out before we dive into let
and const
is hoisting.
既然我们已经讨论了变量声明,初始化和作用域,那么在深入研究let
和const
之前,我们需要清除的最后一件事。
Remember earlier we said that "In JavaScript, variables are initialized with the value of undefined
when they are created.". Turns out, that's all that "Hoisting" is. The JavaScript interpreter will assign variable declarations a default value of undefined
during what's called the "Creation" phase.
还记得前面我们说过的:“在JavaScript中,变量在创建时会用undefined
值初始化。” 事实证明,这就是“吊装”的全部内容。 JavaScript解释器将在“创建”阶段为变量声明分配默认值undefined
。
For a much more in depth guide on the Creation Phase, Hoisting, and Scopes see
有关创建阶段,提升和合并范围的更深入的指导,请参阅
Let's take a look at the previous example and see how hoisting affects it.
让我们看一下前面的示例,看看提升如何影响它。
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}
Notice all the variable declarations were assigned a default value of undefined
. That's why if you try access one of those variables before it was actually declared, you'll just get undefined
.
注意,所有变量声明都被分配了默认值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}
Now that you know everything there is to know about var
, let's finally talk about the whole point of why you're here, what's the difference between var
, let
, and const
?
既然您已经了解了有关var
所有知识,那么让我们最后谈谈您为什么在这里的全部要点, var
, let
和const
什么区别?
First, let's compare var
and let
. The main difference between var
and let
is that instead of being function scoped, let
is block scoped. What that means is that a variable created with the let
keyword is available inside the "block" that it was created in as well as any nested blocks. When I say "block", I mean anything surrounded by a curly brace {}
like in a for
loop or an if
statement.
首先,让我们比较var
和let
。 var
和let
之间的主要区别在于, let
是块范围的,而不是函数范围的。 这意味着用let
关键字创建的变量在创建的“块”以及任何嵌套块中都可用。 当我说“ block”时,是指用花括号{}
包围的所有内容,例如for
循环或if
语句。
So let's look back to our discountPrices
function one last time.
因此,让我们最后一次回顾我们的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}
Remember that we were able to log i
, discountedPrice
, and finalPrice
outside of the for
loop since they were declared with var
and var
is function scoped. But now, what happens if we change those var
declarations to use let
and try to run it?
请记住,我们可以登录i
, discountedPrice
和finalPrice
外面for
循环,因为他们与申报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) // ❌ ReferenceError: i is not defined
?♀️ We get ReferenceError: i is not defined
. What this tells us is that variables declared with let
are block scoped, not function scoped. So trying to access i
(or discountedPrice
or finalPrice
) outside of the "block" they were declared in is going to give us a reference error as we just barely saw.
We️我们得到ReferenceError: i is not defined
。 这告诉我们,用let
声明的变量是块范围的,而不是函数范围的。 因此,试图访问i
(或discountedPrice
或finalPrice
)之外他们是想给大家一个参考的错误,因为我们只是勉强锯被宣布的“块”的。
var VS letvar: function scopedlet: block scoped
The next difference has to do with Hoisting. Earlier we said that the definition of hoisting was "The JavaScript interpreter will assign variable declarations a default value of undefined
during what's called the 'Creation' phase." We even saw this in action by logging a variable before it was declared (you get undefined
)
下一个差异与起重有关。 之前我们说过,提升的定义是“ JavaScript解释器将在“创建”阶段为变量声明分配默认值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}
I can't think of any use case where you'd actually want to access a variable before it was declared. It seems like throwing a ReferenceError would be a better default than returning undefined
. In fact, this is exactly what let
does. If you try to access a variable declared with let
before it's declared, instead of getting undefined
(like with those variables declared with var
), you'll get a ReferenceError.
我想不出任何用例,您实际上要在声明变量之前访问它。 似乎抛出ReferenceError比返回undefined
更好。 实际上,这正是let
所做的。 如果尝试在声明之前访问用let
声明的变量,而不是获取undefined
变量(如使用var
声明的变量),则将得到ReferenceError。
function discountPrices (prices, discount) { console.log(discounted) // ❌ 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 letvar: function scoped undefined when accessing a variable before it's declaredlet: block scoped ReferenceError when accessing a variable before it's declared
Now that you understand the difference between var
and let
, what about const
? Turns out, const
is almost exactly the same as let
. However, the only difference is that once you've assigned a value to a variable using const
, you can't reassign it to a new value.
既然您已经了解了var
和let
之间的区别,那么const
呢? 事实证明, const
与let
几乎完全相同。 但是,唯一的区别是,一旦使用const
将值分配给变量后,就无法将其重新分配给新值。
let name = 'Tyler'const handle = 'tylermcginnis'name = 'Tyler McGinnis' // ✅handle = '@tylermcginnis' // ❌ TypeError: Assignment to constant variable.
The take away above is that variables declared with let
can be re-assigned, but variables declared with const
can't be.
上面的要点是,可以重新分配用let
声明的变量,但不能重新分配用const
声明的变量。
Cool, so anytime you want a variable to be immutable, you can declare it with const
. Well, not quite. Just because a variable is declared with const
doesn't mean it's immutable, all it means is the value can't be re-assigned. Here's a good example.
很酷,因此任何时候只要您希望变量是不可变的,都可以使用const
声明它。 好吧,不完全是。 仅仅因为用const
声明了一个变量并不意味着它是不可变的,而是意味着该值不能被重新分配。 这是一个很好的例子。
const person = { name: 'Kim Kardashian'}person.name = 'Kim Kardashian West' // ✅person = {} // ❌ Assignment to constant variable.
Notice that changing a property on an object isn't reassigning it, so even though an object is declared with const
, that doesn't mean you can't mutate any of its properties. It only means you can't reassign it to a new value.
请注意,更改对象的属性不会重新分配它,因此,即使使用const
声明了对象,也不意味着您无法更改其任何属性。 这仅意味着您无法将其重新分配为新值。
Now the most important question we haven't answered yet, should you use var
, let
, or const
? The most popular opinion, and the opinion that I subscribe to, is that you should always use const
unless you know the variable is going to change. The reason for this is by using const
, you're signalling to your future self as well as any other future developers that have to read your code that this variable shouldn't change. If it will need to change (like in a for
loop), you should use let
.
现在,我们尚未回答的最重要的问题是,您应该使用var
, let
还是const
? 最受欢迎的观点以及我赞成的观点是,除非您知道变量将要更改,否则应始终使用const
。 这样做的原因是通过使用const
,您可以向将来的自己以及其他任何必须阅读此代码不应更改此代码的将来的开发人员发出信号。 如果需要更改(例如在for
循环中),则应使用let
。
So between variables that change and variables that don't change, there's not much left. That means you shouldn't ever have to use var
again.
因此,在变化的变量和不变的变量之间,剩下的不多了。 这意味着您不必再使用var
。
Now the unpopular opinion, though it still has some validity to it, is that you should never use const
because even though you're trying to signal that the variable is immutable, as we saw above, that's not entirely the case. Developers who subscribe to this opinion always use let
unless they have variables that are actually constants like _LOCATION_ = ...
.
现在,尽管它仍然具有一定的有效性,但不受欢迎的观点是,您永远不应该使用const
因为即使您试图像上面那样看到信号变量是不可变的,也不完全是这种情况。 订阅此意见的开发人员始终使用let
除非他们具有实际上是常量的变量,例如_LOCATION_ = ...
So to recap, var
is function scoped and if you try to use a variable declared with var
before the actual declaration, you'll just get undefined
. const
and let
are blocked scoped and if you try to use variable declared with let
or const
before the declaration you'll get a ReferenceError. Finally the difference between let
and const
is that once you've assigned a value to const
, you can't reassign it, but with let
, you can.
因此,回顾一下, var
是函数范围的,如果尝试在实际声明之前使用var
声明的变量,则只会得到undefined
。 const
和let
被限制作用域,如果您尝试在声明之前使用let
或const
声明的变量,则会得到ReferenceError。 最后, let
和const
之间的区别在于,一旦您为const
分配了一个值,就无法重新分配它,但是使用let
可以。
var VS let VS constvar: function scoped undefined when accessing a variable before it's declaredlet: block scoped ReferenceError when accessing a variable before it's declaredconst: block scoped ReferenceError when accessing a variable before it's declared can't be reassigned
翻译自:
转载地址:http://eywzd.baihongyu.com/