ES6中的let与var的区别(浅析函数闭包、同步异步)

news/2024/7/11 1:35:38 标签: es6, javascript, 函数闭包, 同步

目录

  • 前言
  • let与var 的区别
    • let
    • var
      • 同步异步的区别
      • 异步执行的概念
      • 使用var达到正常效果
  • 函数闭包
  • const的注意事项与内存模型的浅析
  • 基本数据类型与复杂数据类型
    • 基本数据类型
    • 引用(复杂)数据类型
  • 浅析浅拷贝与深拷贝

前言

理解let与var的时候会涉及到作用域与变量提升的知识,而var是js创建时候遗留下来的小弊端,存在很多麻烦,let的出现就是为了解决作用域的问题。而这些与函数的闭包密切相关,说起函数闭包,不得不提及js执行机制中的同步与异步的概念与区别,然后牵扯到执行栈与任务队列,再究其本质,实际上应该是内存空间分布的问题,即堆和栈存放了哪些数据类型,const的定义常量涉及到了内存模型,而这又让我想起了深拷贝与浅拷贝的区别,所以本文讲的可能有点多,逻辑关系或许没有处理的特别好~

let与var 的区别

let

ES6引进了块级作用域的概念,在ES5之前只有函数作用域,因此会形成函数闭包

var

存在变量提升,很多情况下会有麻烦
先看一个常见的例子:

javascript">for (var i = 0; i < 5; i++) {
            setTimeout(function() {
                console.log(i);
            }, 1000);
        }

结果输出的是
5
5
5
5
5
再对比let:

javascript">for (let i = 0; i < 5; i++) {
            setTimeout(function() {
                console.log(i);
            }, 1000);
        }

结果输出是
0
1
2
3
4


使用var定义的时候,i存在变量提升,可以每个循环都让i的值加一,最后i=4的时候符合4<5的条件,还有一次i++自增,此时i的值变成了5
全局作用域下,i=5提升到最前面,每个for循环中的i的值都是5。


使用let定义的时候,由于引入了块级作用域的概念,let只在当前作用域生效,即i在当前循环中的值是什么,就直接能输出什么。


此外,仔细观察会发现,定时器的加入,过了一秒之后是全部结果都一下子显示出来,那是因为在for循环遍历完成之后才开始的进行定时器的事件。这也是js中setTimeout定时器的异步执行机制

同步异步的区别

"同步模式"就是后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。

"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。


异步执行的概念

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。


因此可以解释上面定时器的原因
for循环对i进行自增赋值,这些是同步任务,发生在执行栈中,而后面接了一个是定时器,是异步任务,定时器函数放在任务队列中,此时栈中由下到上是 i=01234,分别指向的是定时器一秒过后输出i的值,而虽然都是一秒后输出,但都是才任务队列中,异步进行,全部一起执行,即一秒之后全部输出i对应的值。


使用var达到正常效果

可以使用立即执行函数也能达到let块级作用域的效果
实际上也是使用了闭包,来解决这个问题
因为函数也是一个作用域
里面的j一旦赋予给了函数里面,外面改变也不会影响里面的值

javascript">for (var j = 0; j < 5; j++) {
            (function(num) {
                setTimeout(function() {
                    console.log(num);
                }, 1000);
            })(j)
        }

这种方法相当于开辟了五个单独的函数作用域,闭包并不会不会消失
只不过用的比较少


函数闭包

javascript">		var name = 'why';
        abc(name);
        function abc(name) {
            console.log(name);
        }
        name = 'who';
        abc('aaa');
        abc('bbb');
        abc(name);

结果:

abc()函数里面传入的参数,形成了函数闭包,第一个abc()函数里面的值是why没有改变,第二个abc()函数的值是who,因为函数下方对name进行了重新赋值

简单来说,第一个函数里面传入了形参,输出的值不会改变;第二个改变是因为传入的形参发生了改变而改变。

但闭包可能会存在着内存泄漏~

var有点像多个线程共享同一个资源,而let是每个线程都有自己的资源~


const的注意事项与内存模型的浅析

讲了var与let,不得不提及ES6中的const
其实const在很多语言都有出现,实际上就是使用const定义了的值不能再改变,也就是变成了常量,而var和let定义的都是变量。
let定义的变量在块级作用域内是不能改变的,也就是不能重复声明,而var是全局变量,都可以改变与重新赋值。


const声明的常量必须赋值;const赋值之后的常量不能再修改;常量的含义是指向的对象不能修改,但可以改变对象内部的值

javascript"> const obj = {
            name: '小a',
            age: 18,
            height: 183,
        }
        console.log(obj);
        obj.name = '小b';
        obj.age = 28;
        obj.height = 188;
        console.log(obj);

输出结果:
在这里插入图片描述


内存模型:

在这里插入图片描述
const修饰,存的是内存地址,不能改变,但可以修改里面对象指向的值,因为并不会影响obj的地址数值


基本数据类型与复杂数据类型

基本数据类型

String、Number、Boolean、Undefined、Null、Symbol(es6新增)
基本数据类型直接存储在栈中

引用(复杂)数据类型

Object
存储的是该对象在栈中引用,真实的数据存放在堆内存中


引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。
当解释器寻找引用值的时候,会首先检索在栈中的地址,取得地址后从堆中获取实体。


浅析浅拷贝与深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

内存模型:
在这里插入图片描述


http://www.niftyadmin.cn/n/1184383.html

相关文章

深入浅出MySQL重印

今天接到编辑通知&#xff0c;<<深入浅出MySQL>>将重印1500册&#xff0c;这也是上市5个月来的首次重印&#xff0c;无疑对我们是个莫大的鼓舞和激 励。这次再版会修改第一版中发现的一些错误&#xff0c;并且在最后一章中加入mysql proxy的内容&#xff0c;希望广…

vscode插件——个人版1.0

文章目录1&#xff0c;&#xff08;*&#xff09;Auto Close Tag2&#xff0c;&#xff08;*&#xff09;Auto Rename Tag3&#xff0c;&#xff08;*&#xff09;Better Comments 注释人性化高亮显示4&#xff0c;&#xff08;*&#xff09;Bracket Pair Colorizer 彩虹括号5&…

本blog建立安全技术QQ群

本blog建立安全技术研究QQ群&#xff0c;群号&#xff1a;61193014要求&#xff1a;&#xff08;1&#xff09;任何热爱安全技术的朋友都可以参加&#xff08;2&#xff09;本群不从事黑站、盗号等所有非法活动&#xff0c;仅从事安全技术研究。&#xff08;3&#xff09;谢绝闲…

vscode常用快捷键——个人版1.0

1&#xff0c;删除光标之后的一个单词 CtrlDelete 2&#xff0c;删除光标之前的一个单词 CtrlBackspace 3&#xff0c;删除行 CtrlShiftX 4&#xff0c;删除该行并保留在粘贴板中 CtrlShiftX 5&#xff0c;选择单词 CtrlShift方向键 6&#xff0c;单词间的移动 Ctrl方向键&…

在jtable中显示数据库信息

1://一.新建一表格视图(MVC的View) JTable JTableView new JTable();2://二.新建一表格模板(MVC的Model) DefaultTableModel JTableModel new DefaultTableModel();3://三.新建createTableModel()方法 private void createTableModel() { //…

ASP.NET AJAX DropShadow 控件的一个BUG和解决方法(a bug of DropShadow and solution to resolve)...

DropShadow 控件&#xff1a;http://www.asp.net/AJAX/AjaxControlToolkit/Samples/DropShadow/DropShadow.aspx 既方便又使用&#xff0c;给广大新手们带来了很大的便利&#xff0c;可以轻松的为Panel&#xff08;DIV&#xff09;等控件制作出圆角阴影效果&#xff0c;只需要如…

经历过的一些前端面试题(春招)

文章目录1&#xff0c;你对MVVM的理解2&#xff0c;js的基本数据类型有哪些3&#xff0c;cookies、sessionStorage、localStorage的区别4&#xff0c;垂直居中的几种方式5&#xff0c;null是不是object6&#xff0c;回流与重绘区别&#xff0c;什么样的操作会造成7&#xff0c;…

AutoCAD中图形统计信息

8.7.1 图形统计的功能和使用用户可以在AutoCAD中使用“status”命令查询当前图形的基本信息&#xff0c;如当前图形范围、各种图形模式等。该命令的调用方法为&#xff1a;菜单&#xff1a;【Tools&#xff08;工具&#xff09;】→【Inquiry&#xff08;查询&#xff09;】→【…