When to use var vs let vs const in JavaScript

原文javascript

medium.freecodecamp.org/var-vs-let-…java

在这篇文章中,你将会在javascript(ES6)中学习两种新的方式建立变量,let和const。在此过程当中,咱们将看到var,let和const的不一样之处,以及包括诸如函数与块做用域、变量提高和不变性等主题编程

ES2015(或者ES6)介绍了两种新的方式建立变量,let和const。可是在咱们真正区分var,let和const不一样点以前,你应该先了解一些前提条件。它们是变量声明vs初始化,做用域(特别是函数做用域),和变量提高数组

Variable Declaration vs Initializationbash

变量声明vs初始化编程语言

一个变量声明介绍了一个新的标识符ide

var declaration复制代码

上面咱们建立了一个新的标识符叫作声明。在javascript中,当变量被建立,它们以undefined的值被初始化。这意味着,若是咱们尝试打印声明的变量,咱们将获得undefined函数

var declaration
console.log(declaration)复制代码

因此若是咱们打印声明的变量,咱们获得undefined学习

与变量声明相反,变量初始化是指当你首次给一个变量赋值ui

var declaration
console.log(declaration) // undefined
declaration = 'This is an initialization'复制代码

因此在这里咱们经过赋值给已经声明当变量一个字符串来初始化它。

这就引导咱们第二个概念了,做用域

Scope(做用域)

做用域定义了在你的程序里,变量和函数在哪里能够获取到。在JavaScript中,有两种类型的做用域--全局做用域和函数做用域,根据官方的规范,

若是变量语句发生在函数声明中,则变量在这个函数中经过函数局部做用域来定义

这就意味着若是你使用var来建立一个函数,那么这个变量被运用于它所建立的函数,而且只能在该函数内部或者任何嵌套函数内部被访问。

function getDate () {
  var date = new Date()
  return date
}
getDate()
console.log(date) // ❌ Reference Error复制代码

上面咱们尝试获取一个被声明的函数以外的变量。由于date是做用域于getDate的函数,它只能被getDate它自己或者getDate中的任何嵌套函数所获取(以下所示)

function getDate(){
    var date = new Date()
    function formatDate(){
        return date.toDateString().slice(4) //可获取
    }
    return formatDate()
}
getDate()
console.log(date) // Reference Error 引用错误复制代码

如今让咱们来看一个更高级的例子。假设咱们有一个prices的数组,而且咱们须要一个函数,这个函数接收一个像折扣的数组,而且返回一个折扣后的新数组。最后的目标可能看起来像这样:

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循环以外,这没有一个理由仍然可以访问到i,discountedPrice,和finalPrice。它不会对咱们有任何的好处,而且甚至可能在必定程度上对咱们形成伤害。然而,由于用var声明的变量是函数做用域的,因此你能够这样作。

如今咱们已经能够讨论过变量声明,初始化,和做用域,那么在咱们深刻了解let和const以前咱们须要清除的最后一件事就是提高。

Hoisting提高

记得早的时候咱们说过,‘在JavaScript中,变量被建立时能够用undefined值来初始化。事实证实,这就是“Hoisting”的所有。JavaScript解析器在被“建立”的阶段将分配一个默认的值undefined给变量的声明。


寻找更多更深刻关于建立阶段,提高和做用域的指南,能够参阅 The Ultimate Guide to Hoisting, Scopes, and Closures in 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的每一件事,让咱们最后讨论你为何在这的重点:var,let和const的区别在哪里?

var VS let VS const

首先,让咱们比较var和let。var和let主要的不一样点不是函数做用域,let是块做用域。

这就意味着一个变量用let关键字建立能够被“块”内部以及任何嵌套的块中所访问。当我说“块”时,我是指像在一个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循环以外打印i,discountedPrice和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) // 3
  console.log(discountedPrice) // 150
  console.log(finalPrice) // 150
  return discounted
}
discountPrices([100, 200, 300], .5) // ❌ ReferenceError: i is not defined复制代码

咱们获得ReferenceError: i is not defined.这告诉咱们的是,用let声明变量是块做用域而不是函数做用域。因此尝试在它们声明的“块”以外访问i(或者discountedPrice or finalPrice)将给咱们一个引用错误,正如咱们刚才所看到的。

var VS let
var: function scoped
let: block scoped复制代码

下一个区别与提高相关。以前咱们说过,提高的定义是“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
}复制代码

我想不到任何你想要在声明变量以前访问变量的案例。这看起来就像抛出一个引用错误也比返回undefined更好

事实上,这就是let作的事情。若是你尝试在声明以前访问一个用let声明过的变量,而不是获得undefined(就像用var声明那些变量),你将获得一个引用错误

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 let
var: 
  function scoped
  undefined when accessing a variable before it's declared let: block scoped ReferenceError when accessing a variable before it's declared复制代码

let VS const

如今你理解了var和let的区别,那么const呢?事实上,const更像是let,然而,惟一的不一样点就是你一旦用const分配了一个变量的值,你将不能从新分配一个新的值。

let name = 'Tyler'
const handle = 'tylermcginnis'
      name = 'Tyler McGinnis' // ✅
handle = '@tylermcginnis' // ❌ TypeError: Assignment to constant variable.复制代码

上面的内容用let声明的变量能够从新赋值,可是用const声明的变量不能

很是酷,因此你只要想一个变量永远不变,你能够用const来声明。固然也不彻底,仅仅由于用const声明一个变量并不意味着它是永远不变的,这彻底意味着值不能被从新赋值。这就是一个很好的例子

const person = {
  name: 'Kim Kardashian'
}
person.name = 'Kim Kardashian West' // ✅
person = {} // ❌ Assignment to constant variable.复制代码

注意,在一个对象上改变一个属性并非从新赋值,因此即便一个对象用const声明,也不意味着你不能改变它的属性。这仅仅意味你不能从新分配一个新值

如今咱们尚未回答最重要的问题是:你应该使用var,let或者const?最受欢迎的观点和我表述的观点是,你应该老是使用const,除非你知道变量将发生改变。这么作的缘由是使用const,你向将来的本身以及必须阅读你代码的任何将来的开发者们发出信号,这个变量不该该改变。若是它将须要改变(像在for循环中),你应该使用let

因此,在可变的变量与不可改变的变量之间,就没有太多的东西剩下。这意味着你不该该再使用var

总结

var是函数做用域,而且若是你尝试在实际声明以前使用一个var声明的变量,你将获得undefined。

const和let是块做用域,而且若是你尝试在实际声明以前使用let或const声明的变量,你将获得一个引用错误。

最后在let和const之间的区别是一旦你用const分配了一个值,你将不行从新赋值,可是用let能够

相关文章
相关标签/搜索