var、let、const

var、let、const

1. var变量提升:

(function shiftup(){
  if(false){
    var show1='a'
  }
  console.log(show1)
  console.log(show)
})()

在这个函数中,正确的执行应该是这两条打印都会未定义的错误,但是现实是只有第二条打印报错,第一条打印出来是undefined,undefined意味着这个函数已经被定义但是没有被赋值。

这是因为var有变量提升,这段代码实际上等于

(function shiftup(){
  var show1//变量提升
  if(false){
    show1='a'
  }
  console.log(show1)
  console.log(show)
})()

2. let&const暂时性死区TDS

function func1(){
  console.log(a)
  // 这个往上的空间是暂时性死区,是读不到a变量的
  let a='hello'
}
func1()

这里的a就会报错,这样的方式更好

在函数参数中也有这样的情况

function func2(a=b,b=3){}
func2()

编译器会报错:ReferenceError: Cannot access 'b' before initialization这是因为对于b来说,a=b被调用是,b还没有被赋值,是在TDS中的

当改成:

function func3(a=3,b=a){}
func3()

就不会报错,此时的b=3

3. let、var、const的共同点

在全局定义都是可以被访问的

// const web='hello qiaomu'
// let web='hello qiaomu'
var web='hello qiaomu'
function show(){
  console.log(web)
}
show()

如果在函数内有一个web变量时,情况就会发生改变

var web='hello qiaomu'
function show(){
  var web='hello mumu'
  console.log(web)//hello mumu
}
show()
console.log(web)//hello qiaomu

当内部不声明变量时,改的变量是全局的web变量

var web='hello qiaomu'
function show(){
  web='hello mumu'
  console.log(web)//hello mumu
}
show()
console.log(web)//hello mumu

练习:

const web='hello qiaomu'
function show(){
  const web='mumu'
  function run(){
    var web='run mumu'
    console.log(web)//run mumu
  }
  run()
  console.log(web)//mumu
}
show();
console.log(web)//hello qiaomu

(要放在浏览器运行,在code run中会报错)

函数是一个私有领地,只有当私有领地中没有才会去全局找

4. 不同点1:块级作用域

var是没有块级作用域概念的

情况1:

var i=99
console.log(`全局${i}`)
for(var i=0;i<5;i++){
  console.log(`局部${i}`)
}
console.log(`全局${i}`)

在上面的代码中,最后一个全局的i的值打印为5,也就是说for循环把全局i的值给改了,var是没有块级作用域的,这不是我们希望看到的结果,把for循环中的i用let声明就可以解决这个问题

情况2

在1.js中

var name='mumu'

在2.js中

var name='qiaomu'

先引入1.js,再引入2.js,当打印这个name时显示的是qiaomu,如果调换顺序,打印就被改成了mumu,这是因为这两个js是在一个作用域里面

方法1:立即执行函数

在原来要解决这个问题一般是用一个自执行函数

(function(){
  var $=(window.$={})
  $.web='qiaomu'
  var url='qiaomu.com'
  $.getUrl=function(){
      return url;
  }
}.bind(window)());

这里的变量都是定义在这个函数里面,通过var = ( w i n d o w . =(window. =(window.={})把变量开放给外部接口。在外部如果直接读url是读不了的,在外面***使用$.getUrl()***才能读到这个url的值。立即执行函数是控制作用域,防止全局污染。

方法2:使用{}

{
  let $=(window.$={})
  $.web='qiaomu'
  let url='qiaomu.com'
  $.getUrl=function(){
      return url;
  }
}

在外部访问时也是一样使用***使用$.getUrl()***才可以访问到url,要注意的是这里不可以使用var,因为使用var是没有块级作用域的

5. const详解

const variate1='qiaomu'
let variate2='mumu'
variate1='mumu'//报错
variate2='qiaomu'//不报错

const是不可以修改的(在同一个作用域中不可改),const实际上是对内存地址的引用

所以当const的值是个引用类型,该引用的数据是可以的,例如:

const CONFIG={}
CONFIG.url='qiaomumu 好可爱!'
console.log(CONFIG.url)//qiaomumu 好可爱!

因为声明一个变量的时候本质上是把一个地址赋值给这个变量,所以当这个值为一个基本类型时,这个变量中存储的地址是直接指向这个数字的,const声明的变量不可以改变内存地址,也就不可以改变这个值。但是如果这个变量是一个引用类型,引用类型本来就是一个地址,就相当于const声明的变量中保存一个地址,这个地址指向另一个地址,这个另一个地址才是真正的值,所以当改变这个另一个地址中的值的时候相当于改变这个const变量中的值。

Object freeze冻结变量

有的时候我不希望我的引用类型被改变,显然这时候用const是不可以的,因为const并不能控制自己存的地址的地址的变量不被改变,所以这时候使用Object.freeze(variate)来使引用类型的变量的值不可以被改变

//"use strict"如果使用严格模式,HOST.port='3003'这句会报错
const HOST={
  url:'www.qiaomu.com',
  port:'8080'
}
Object.freeze(HOST)// 冻结变量
HOST.port='3003'
console.log(HOST)

6. 不同点2:var导致的window全局对象污染

var会把变量放到windows中,但是let不会

var m_name1='qiaomu_var'
console.log(window.m_name1)//qiaomu_var
let m_name2='mumu_let'
console.log(window.m_name2)//undefined

把变量放到window全局对象中是非常不合理的,因为当定义的变量与原本window的某些属性重名时,会导致dom或bom的操作错误。let可以避免这些问题。

7. 不同点3:var重复声明

const和let在同一作用域中重复声明是不可以的,会报错,但是如果是var是可以的

const web='hello qiaomu'
function show2(){
  const web='mumu'
  function run(){
    let web='run mumu'
    console.log(web)//run mumu
  }
  run()
  console.log(web)//mumu
}
show2()

这里作用域不同所以声明没有关系

const a='qiaomu'
let a='mumu'

但是如果代码编程了这样就会报错:Identifier 'a' has already been declared

8. 标量与引用类型的传值与传址

对于基本类型来说,赋值是传值

let a=1;
let b=a;
console.log(a,b);//1 1
b=3;
console.log(a,b);//1 3

从上面的代码可以看出,b=a是把值给了b,因为如果是a把地址给了b,那么当b改变值时,a的值也会变,但是事实是a的值没有变,只是b的值变了,也就是说程序重新开辟了一块内存存储3,并把这个地址赋值给了b

但是对于引用类型不是这样,因为引用类型通常值很大,占用内存多,所以在赋值是会传址

let c={name:'mumu'};
let e=c;
console.log(e,c);//{ name: 'mumu' } { name: 'mumu' }
e.name='qiaomu';
console.log(e,c)//{ name: 'qiaomu' } { name: 'qiaomu' }

就像上面的打印结果是改了e.namec.name也被改变了。

9、null和undefined

  • 引用类型初值是null,基本类型初值是undefine

  • 函数没有返回值时,默认返回undefined

  • 函数没有传参是,默认值是undefined

  • 声明了没有赋值的变量类型是undefined

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值