var let const 详细区别

2023-05-16

用了ES6已经有一段事件了,也看了很多文档,以前觉得不用写一个文档总结,但是经过一段时间的接触以后,认为自己还是有必要去吧他们的区别详详细细的总结一下

块级作用域

白话一点就是在{}中就是一个块级作用域,那么这个块级作用域有什么作用呢?

第一种场景,内层变量可能会覆盖外层变量

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined

上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升(虽然这里if为false但是还是会变量提升,只是不会执行tmp = 'hello world';),导致内层的tmp变量覆盖了外层的tmp变量。

第二种场景,用来计数的循环变量泄露为全局变量

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

let和const实际上为 JavaScript 新增了块级作用域

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

let和const只在各自块级作用域中有效

在不同的作用域下,会有不同的各自的变量,常量

let n = 5;
function f1() {
  let n = 50;
  {
    let n = 10
  }
  console.log(n); //50
}
f1();
console.log(n); //5

如果是用var声明的化 就会有不一样的打印值

关于这个不同大表现值还有一个例子很有表现力-----for()循环

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

这里的答案为什么会是10,为什么不是6,因为当我们执行a[6]()这个函数的时候因为ES5中没有块级作用域所以他会在a[6]()这个函数作用域去找i的值,但是没有只可以去找全局了,那么这个时候全局中的i等于10,所以答案为10

但是如果我们用ES6 的let 来声明变量那么因为let会为js新增块级作用域,所以每一给for循环出来的{}中都有他们自己定义出来的i就不用去找全局的了

let a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}

    .
    .
当i=1的时候
{
  let i= 1
  a[1] = function(){
    console.log(1);
   }
 }
    .
    .
    .

就是上面这样一个表现的代码形式,也就是说循环体内部是一个单独的子作用域

let 和 const 不存在变量提升 但是却有暂时性死区(这个要注意)

只要块级作用域内存在let,const命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响,切不会提升

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

这里报错是因为在这个块级作用域中有声明tmp的这个举动但是赋值却在声明的下面所以报错,也就是说在一个块级作用域中,只要声明了某一个变量,这个变量补单不会提升,并且这么块级作用域就相当于是这个变量的暂时性死区,不会去向上一个层级去找变量,也就是说一定在块级作用域下要先声明在赋值,(这个也是一个必须要有的品质)

暂时性死区的特别案例

y=4
function bar(x = y, y = 2) {
  return [x, y];
}

bar(); // 报错

因为x=y的过程中y还没被定义函数中的形参的定义是定义在函数内部的,不是函数外,所以这里外部的y=4是没效果的

// 不报错
var x = x;

// 报错
let x = x;
// ReferenceError: x is not defined

这里x没定义就被赋值了,其实也是同一个道理

let不允许重复声明,但可以改变值,const是定义一个常量那么连值都不可以去改变

但是这里const值不可以变有一份地方需要注意就是当const定义的是一个指针(对象名,引用类型)的时候,那么是指针指向的地址不变就可以了,地址里的东西变了是关系的?为什么呢?我们假设一下:我们用const定义了一把钥匙,我们只要求钥匙不变我们是管不了钥匙他可以开的那个们不管他变不变,反正我们定义的是那个钥匙对吧。

function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}
function func(arg) {
  let arg;
}
func() // 报错

function func(arg) {
  {
    let arg;
  }
}
func() // 不报错

块级作用域与函数声明

在块级作用域中不要用函数声明,最后是要用函数表达式,为什么呢? 马上就知道了

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。

在ES5中:

function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());

上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。

// ES5 环境
function f() { console.log('I am outside!'); }

(function () {
  function f() { console.log('I am inside!'); }
  if (false) {
  }
  f();
}());

在ES6中:

ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,这是为什么呢?

原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部,赋值为undefined
  • 同时,函数声明还会提升到所在的块级作用域的头部。(整个函数)

上面的例子实际运行的代码如下

// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function

 大家可以试一试,讲道理确实麻烦所以我以后应该是不会在块级作用域中使用函数声明了,用函数表达式

/ 块级作用域内部的函数声明语句,建议不要使用
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 块级作用域内部,优先使用函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

 ES6声明变量的六种方法

 var function  ES6:let const import class

顶层对象的属性

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

var let const 详细区别 的相关文章

随机推荐

  • js深度拷贝和浅度拷贝的深入理解

    首先我们来说说什么是拷贝 xff1a 就是复制的同时加上了传值 然后问题就来了什么是有深度的什么是浅度的 xff0c 在想要了解我们这个问题之前我们先来了解一下下面的一个知识点 基本类型传递 xff0c 引用类型传递 首先我们来看下基本类型
  • npm的基本使用

    npm的下载 npm的下载其实就是把node js 百度下node官网 下载好了那么npm就附带下载好了 检查是否下载好 window 43 r 后输入cmd打开终端 xff0c 在终端中输入node v xff1b npm v 他们会输出
  • 从 (a==1&&a==2&&a==3) 成立中看javascript的隐式类型转换

    几天上班看到一个题目就是 if a 61 61 1 amp amp a 61 61 2 amp amp a 61 61 3 console log 34 a等于什么才会输出这一句话呢 xff1f 34 当a为什么的时候输出 xff1a a等
  • Bootstrap实用功能总结

    导航栏 xff1a navbar 导航栏容器可以包含以下几个常用组成 xff1a 1 品牌LOGO xff08 navbar brand xff09 2 导航菜单 xff08 navbar nav xff09 3 导航文本 xff08 na
  • 微信小程序的AJAX初次体验

    GET请求 微信小程序用GET传送数据 微信小程序通过 wx request发送ajax请求 wx request url app globalData pubSiteUrl 43 39 user information get infor
  • vue总结系列 ------ 组件之间的传值

    原因 半年前开始学Vue学到了今天 xff0c 也没有机会好好整理一下自己的知识点 xff0c 因为上公司的项目不是依赖于Vue xff0c 还是在用JQ 和文件之间来传递代码 xff0c 所以其实在对vue的学习成面上来讲对我的帮助并不大
  • vue总结系列 --- 插槽slot

    前因 这个是我这个系列的第二篇 这一篇文章我也修改过三次 xff08 2019 9 10 xff09 我是想以vue官方文档为基础 xff0c 来进行理解 xff0c 有人说有官方文档 xff0c 还要写自己的文章干嘛 xff0c 我的用意
  • vue总结系列 --- 生命周期

    前言 在总结其他的时候发现还是应该先复习vue的生命周期 xff0c 所以就先把生命周期先复习完了 经过一系列的视频 xff0c 文档我把我的总结写一下生命周期分为3个阶段 xff1a 创建 xff0c 更新 xff0c 和销毁 我们看图说
  • vue总结系列 ---- 响应式原理

    检测变化 vue是数据驱动的视图框架DOM是通过数据映射的 xff0c 只有数据改变 xff0c DOM才改变 那么数据是怎么来的呢 xff1f 1 来自父元素的属性 xff08 prop xff09 2 来自组件的自身状态 xff08 d
  • Object.defineProperty()的学习了解

    背景 最近在总结vue系列的时候是看到响应原理的时候 看到一个新的知识点也就是我们的标题Object defineProperty 的时候 xff0c 好了话不多说 xff0c 我们来看看这个是怎么使用的 开始 strong Object
  • vue总结系列 ----- 单向数据流

    可能很多人都以为vue的双向绑定其实是错误的 xff0c vue真正的是单向数据流 xff0c vue的双向绑定只不过是语法糖 我的理解是 xff1a model层 xff1a data对象中的数据 xff0c 或后台传过来的数据 view
  • vue总结系列 ---- 在组件上的v-model单向数据流

    背景 目前是在复习vue原理的过程中 xff0c 前端负责人知道我最近在复习vue xff0c 跟我说要我看组件上的v model 我一听本来是不想放在心上的 xff0c 刚好那天晚上没什么事干想看一下 xff0c 毕竟负责人 xff0c
  • ES6 函数扩展

    参数默认值 也就是说现在ES6对函数中的参数添加了默认值 我们在ES5种的处理 function Fn a b b 61 b 34 nodeing 34 return a 43 b console log Fn 34 hello 34 这样
  • ES6 对象扩展

    对象简写 对象中又分了属性和方法的简写 在es5中 xff0c 有这样一种写法 var name 61 34 xiaoqiang 34 var age 61 12 var obj 61 name name age age 在es6中 xff
  • Bootstrap基础学习笔记

    网格系统 row定义一行 col均分列数 xff0c 最多一行12列 每列左右间隙各15px col 1到12 定义在所有屏幕下的列宽 col sm md lg xl 1到12 定义在指定屏幕下该列占据的列宽 xff0c sm 屏幕 gt
  • ES6 Symbol用法

    Symbol用法 什么是Symbol Symbol是es6中一种新增加的数据类型 xff0c 它表示独一无二的值 es5中我们把数据类型分为基本数据类型 xff08 字符串 数字 布尔 undefined null xff09 和引用数据类
  • img标签中的src在绝对引用的时候的问题

    昨天晚上我一个朋友目前在培训 xff0c 他在群里问了下img标签如何绝对路径引用 xff0c 我当时就笑了这个就是培训机构的老师 xff0c 就大概看了一下就告诉我朋友那里错了 xff0c 但是却出来不 xff0c 我就想自己写一个dem
  • 在vue-cli中使用vue-router的学习笔记

    以前不会vue cli的时候学过router xff0c 当时的写法和在vue cli中的写法还是有一些不一样的 xff0c 但是我以后应该还是会用vue的单文件写小程序啊什么的所以我就吧我学习的过程全部记录下来 router创建 那么问题
  • js中bind()使用详情

    前言 最近在在搞React的时候有用到bind 的时候 xff0c 因为他的用法其实我还一直不是特别的清楚 xff0c 所以今天我把bind 他的用法和我遇到的结合起来这样来写一个博客 xff0c 这样应该可以加深自己的印象同时可以来跟好的
  • var let const 详细区别

    用了ES6已经有一段事件了 xff0c 也看了很多文档 xff0c 以前觉得不用写一个文档总结 xff0c 但是经过一段时间的接触以后 xff0c 认为自己还是有必要去吧他们的区别详详细细的总结一下 块级作用域 白话一点就是在 中就是一个块