阿里云最近在作活动,低至2折,有兴趣能够看看:
https://promotion.aliyun.com/...
为了保证的可读性,本文采用意译而非直译。html
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 21 篇。前端
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!git
若是你错过了前面的章节,能够在这里找到它们:程序员
// 声明一些变量并初始化它们 var a = 5 let b = 'xy' const c = true // 分配新值 a = 6 b = b + 'z' c = false // 类型错误:不可对常量赋值
做为程序员,声明变量、初始化变量(或不初始化变量)以及稍后为它们分配新值是咱们天天都要作的事情。github
可是当这样作的时候会发生什么呢? JavaScript 如何在内部处理这些基本功能? 更重要的是,做为程序员,理解 JavaScript 的底层细节对咱们有什么好处。web
下面,我打算介绍如下内容:编程
let
vs const
让咱们从一个简单的例子开始。下面,咱们声明一个名为myNumber
的变量,并用值23
初始化它。segmentfault
let myNumber = 23
当执行此代码时,JS将执行:数组
myNumber
)建立惟一标识符(identifier)。23
存储在分配的地址。虽然咱们通俗地说,“myNumber 等于 23”
,更专业地说,myNumber
等于保存值 23 的内存地址,这是一个值得理解的重要区别。安全
若是咱们要建立一个名为 newVar
的新变量并把 myNumber
赋值给它。
let newVar = myNumber
由于 myNumber
在技术上实际是等于 “0012CCGWH80
”,因此 newVar
也等于 “0012CCGWH80
”,这是保存值为23
的内存地址。通俗地说就是 newVar
如今的值为 23
。
由于 myNumber
等于内存地址 0012CCGWH80
,因此将它赋值给 newVar
就等于将0012CCGWH80
赋值给 newVar
。
如今,若是我这样作会发生什么:
myNumber = myNumber + 1
myNumber
的值确定是 24。可是newVar
的值是否也为 24 呢?,由于它们指向相同的内存地址?
答案是否认的。因为JS中的原始数据类型是不可变的,当 myNumber + 1
解析为24
时,JS 将在内存中分配一个新地址,将24
做为其值存储,myNumber
将指向新地址。
这是另外一个例子:
let myString = 'abc' myString = myString + 'd'
虽然一个初级 JS 程序员可能会说,字母d
只是简单在原来存放adbc
内存地址上的值,从技术上讲,这是错的。当 abc
与 d
拼接时,由于字符串也是JS中的基本数据类型,不可变的,因此须要分配一个新的内存地址,abcd
存储在这个新的内存地址中,myString
指向这个新的内存地址。
下一步是了解原始数据类型的内存分配位置。
JS 内存模型能够理解为有两个不一样的区域:调用堆栈(call stack)和堆(heap)。
调用堆栈是存放原始数据类型的地方(除了函数调用以外)。上一节中声明变量后调用堆栈的粗略表示以下。
在上图中,我抽象出了内存地址以显示每一个变量的值。 可是,不要忘记实际上变量指向内存地址,而后保存一个值。 这将是理解 let vs. const
一节的关键。
堆是存储引用类型的地方。跟调用堆栈主要的区别在于,堆能够存储无序的数据,这些数据能够动态地增加,很是适合数组和对象。
让咱们从一个简单的例子开始。下面,咱们声明一个名为myArray
的变量,并用一个空数组初始化它。
let myArray = []
当你声明变量“myArray
”并为其指定非原始数据类型(如“[]”)时,如下是在内存中发生的状况:
myArray
”)从这里,咱们能够 push
, pop
,或对数组作任何咱们想作的。
myArray.push("first") myArray.push("second") myArray.push("third") myArray.push("fourth") myArray.pop()
vs
const通常来讲,咱们应该尽量多地使用const
,只有当咱们知道某个变量将发生改变时才使用let
。
让咱们明确一下咱们所说的“改变”是什么意思。
let sum = 0 sum = 1 + 2 + 3 + 4 + 5 let numbers = [] numbers.push(1) numbers.push(2) numbers.push(3) numbers.push(4) numbers.push(5)
这个程序员使用let
正确地声明了sum
,由于他们知道值会改变。可是,这个程序员使用let
错误地声明了数组 numbers
,由于他将把东西推入数组理解为改变数组的值。
解释“改变”的正确方法是更改内存地址
。let
容许你更改内存地址。const
不容许你更改内存地址。
const importantID = 489 importantID = 100 // 类型错误:赋值给常量变量
让咱们想象一下这里发生了什么。
当声明importantID
时,分配了一个内存地址,并存储489
的值。记住,将变量importantID
看做等于内存地址。
当将100
分配给importantID
时,由于100
是一个原始数据类型,因此会分配一个新的内存地址,并将100
的值存储这里。
而后 JS 尝试将新的内存地址分配给 importantID
,这就是抛出错误的地方,这也是咱们想要的行为,由于咱们不想改变这个 importantID
的值。
当你将100
分配给importantID
时,其实是在尝试分配存储100
的新内存地址,这是不容许的,由于importantID
是用const
声明的。
如上所述,假设的初级JS程序员使用let
错误地声明了他们的数组。相反,他们应该用const
声明它。这在一开始看起来可能使人困惑,我认可这一点也不直观。
初学者会认为数组只有在咱们能够改变的状况下才有用,const
使数组不可变,那么为何要使用它呢? 请记住:“改变”是指改变内存地址。让咱们深刻探讨一下为何使用const声明数组是彻底能够的。
const myArray = []
在声明 myArray
时,将在调用堆栈上分配内存地址,该值是在堆上分配的内存地址。堆上存储的值是实际的空数组。想象一下,它是这样的:
若是咱们这么作:
myArray.push(1) myArray.push(2) myArray.push(3) myArray.push(4) myArray.push(5)
执行 push
操做实际是将数字放入堆中存在的数组。而 myArray
的内存地址没有改变。这就是为何虽然使用const
声明了myArray,但没有抛出任何错误。
myArray
仍然等于 0458AFCZX91
,它的值是另外一个内存地址22VVCX011
,它在堆上有一个数组的值。
若是咱们这样作,就会抛出一个错误:
myArray = 3
因为 3
是一个原始数据类型,所以生成一个新的调用堆栈上的内存地址,其值为 3
,而后咱们将尝试将新的内存地址分配给 myArray
,因为myArray是用const声明的,因此这是不容许的。
另外一个会抛出错误的例子:
myArray = ['a']
因为[a]
是一个新的引用类型的数组,所以将分配调用堆栈上的一个新内存地址,并存储堆上的一个内存地址的值,其它值为 [a]
。而后,咱们尝试将调用堆栈内存地址分配给 myArray
,这会抛出一个错误。
对于使用const
声明的对象(如数组),因为对象是引用类型,所以能够添加键,更新值等等。
const myObj = {} myObj['newKey'] = 'someValue' // 这不会抛出错误
JavaScript 是世界上排名第一的编程语言(根据GitHub和Stack Overflow的年度开发人员调查)。 掌握并成为“JS忍者”是咱们全部人都渴望成为的人。
任何质量好的的 JS 课程或书籍都提倡使用let, const
来代替 var
,但他们并不必定说出缘由。 对于初学者来讲,为何某些 const 变量在“改变”其值时会抛出错误而其余 const变量却没有。 对我来讲这是有道理的,为何这些程序员默认使用let处处避免麻烦。
可是,不建议这样作。谷歌拥有世界上最好的一些程序员,在他们的JavaScript风格指南中说,使用 const 或 let 声明全部本地变量。默认状况下使用 const,除非须要从新分配变量,不使用 var 关键字(原文)。
虽然他们没有明确说明缘由,但据我所知,有几个缘由
const
声明的变量必须在声明时初始化,这迫使程序员常常在范围方面更仔细地放置它们。这最终会致使更好的内存管理和性能。但愿上面的解释能帮助你开始明白为何或者何时应该在代码中使用 let 和 const 。
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
你的点赞是我持续分享好东西的动力,欢迎点赞!
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,便可看到福利,你懂的。