在项目中尽可能的使用let和const
大家对这句话是不是很熟悉?我们不管看文档还是项目组的人都会说起这几个定义变量的事情,今天小弟给大家说说这几中定义方式的区别
-
var
- 说到var那就要从js的出生说起,在最初的草案中js中的全局变量和顶层变量是完全相等的,也就是全局变量等于window(浏览器)或global(node)
- 我们来看段代码
var name = 'jack';console.log(window.namne) // jack
- 我用var定义了一个变量相当于
window.name = 'jack'
- 其实这种写法也没有什么问题,但是在for里使用大家是不是想起点什么来了?
-
for(var i = 0;i < 5; i++){ setTimeout(() => { console.log(i); }, 1000) } console.log(window.i) // 5 复制代码
- 以为答案是1-5吗?不 其实会输出5次5。
- var存在状态提升 这是i已经是全局变量了,for循环每次循环时看到var就不会重新var而是在本身的基础上++ 所以每次操作的都是全局变量i。打印出来当然是5了
- 不对,等等。
-
为什么for循环里面不写定时器或者ajax或者event事件单单打印i为什么是12345呢?因为在for内部的定时器/ajax/event事件都引用了变量i导致i变量无法被内存机制收回而保存在代码块内部(这里不懂的童鞋可以看看闭包) 复制代码
-
所以在单单打印i或者不对i进行操作的话是一切正常的 复制代码
-
let
- 说清楚了var所存在的问题就来说说let。let的定义在网上一搜一大把我就不献丑了,其实for+let在被js引擎解析的时候就会形成一个局部代码块,在局部代码块里let是唯一的,也就是说不管遇到什么情况for在进行循环时都要执行
let i = xxx
这就保证了每一次的循环都是一个新值 - 下面的图片是我查MDN和咨询我们大佬得出来的结论 大家看看就好啦~
-
- 说清楚了var所存在的问题就来说说let。let的定义在网上一搜一大把我就不献丑了,其实for+let在被js引擎解析的时候就会形成一个局部代码块,在局部代码块里let是唯一的,也就是说不管遇到什么情况for在进行循环时都要执行
-
var存在的变量提升
- 因为作用域链的关系在函数内应该先从函数内寻找变量如果函数内没有在寻找上一级直到寻找到或者undefined 这句话一定要记住!!
-
var num = 10 function fn() { console.log(num) var num = 20 } 复制代码
- 上述代码应该输出多少?这道题面试官不知道问了几次了 划重点!!
- 答案是
undefined
。var声明的变量是有变量提升的 在函数内部我声明了var num = 20 //不管我写在函数哪里都会被提升到函数的最顶部
所以这段代码的顺序是:先执行第一句 定义num并赋值10。走到函数内部引擎发现函数内部有var就把这句提到函数顶部相当于: -
function fn() { 复制代码
-
var num = 20 sonsole.log(num) // 注意!变量提升只是把声明提到了顶部但是没有赋值所以num是 undefined } 复制代码
- 那我们用let定义呢?要记住let是不存在变量提升的所以将代码改为:
-
function fn() { console.log(num) let num = 20 // num is not defined } 复制代码
- 上面说到了作用域链的问题,作用域链其实是引擎寻找变量的过程,会从内部开始寻找一直寻找到最外部。在上面的代码中fn()内部的num首先会找内部的定义如果有就取内部的没有就找上一级。
-
var num = 10 function fn() { console.log(num) var num = 20 } 复制代码
-
这段代码最终的解释是: 由于作用域链我先寻找fn内部的num但由于var存在变量提升到函数顶部 所以我找到了num但是这时的num还是未定义状态最终返回了 undefined
-
const
- 就差最后一个const啦。我们了解es6的童鞋都知道const是定义一个常量用的定义后就不能改变了。
- 但是看下面的代码
-
const obj = {} 复制代码
-
obj.name = 'jack' obj.sex = 'male' 为什么这样不会报错呢? 复制代码
- 我们从js的数据类型说起,数据类型分为:
- 基础数据类型:num string ...
- 复杂数据类型:object array ...
- 基础数据类型没什么好说的 修改他就直接改变他的值了。要说的是复杂类型 在上面
const obj = {}
创建了一个object object是复杂类型他其实是指向的内存和指针obj.name = 'jack'
只是在内存里有加了一条数据并没有直接改变obj的指向所以不会报错。array同理 -
const obj = {} obj = [] 大家说这样会不会报错呢? 复制代码
感悟
- 鲁迅曾经说过 能把自己的知识输出给其他人 才代表你真正懂了
- 我想把自己当时学过的思路和大家分享
- 上面的demo只是最基本的形式,为了方便说明用的都是全局定义
复制代码