JS高级(三):严格模式、闭包、递归、深拷贝和浅拷贝

news2024/11/15 13:52:39

JavaScript高级(三)

  • 一、严格模式
    • 1.开启严格模式
      • (1)为脚本开启严格模式
      • (2)为某个函数开启严格模式
    • 2.严格模式的一些规定
      • (1)禁止变量未声明就赋值
      • (2)禁止删除已声明的变量
      • (3)严格模式下this指向
      • (4)不允许形参有重名
      • (5)不允许在非函数代码块内声明函数
  • 二、闭包
    • 1.什么是闭包?
    • 2.闭包的作用
    • 3.闭包的一些应用
      • (1)点击li打印当前索引号(var)
      • (2)3秒后打印索引号(var)
      • (3)用闭包手撕防抖节流
  • 三、递归
    • 1.什么是递归?
    • 2.递归函数求阶乘
    • 3.递归求斐波那契数列第几个数是谁
    • 4.递归遍历数据
  • 四、深拷贝和浅拷贝
    • 1.浅拷贝
    • 2.手撕深拷贝

一、严格模式

IE10以上的浏览器才支持
在这里插入图片描述

1.开启严格模式

(1)为脚本开启严格模式

<script>
   'use strict'
   //下面的js代码就会按照严格模式来执行
</script>

或者通过立即调用函数:

<script>
    (function() {
        'use strict'
    })();  //立即调用函数
    //下面的js代码就会按照严格模式来执行
</script>

(2)为某个函数开启严格模式

<!-- 给某个函数添加严格模式 -->
<script>
    function fn1() {
        'use strict'
        //里面的代码按照严格模式执行
    }

    function fn2() {
        //里面的代码按照普通模式执行
    }
</script>

2.严格模式的一些规定

(1)禁止变量未声明就赋值

正常模式下一个变量没有声明就赋值默认是全局变量,而严格模式下变量必须先用var或者let,const声明,然后再使用,否则会报错

(2)禁止删除已声明的变量

例如var a = 1; delete a;这种写法会报错

(3)严格模式下this指向

在严格模式下全局作用域的函数中,this指向undefined

<script>
    'use strict'
    //下面的js代码就会按照严格模式来执行
    function fun() {
        console.log(this);  //undefined
    }
    fun();
</script>

注意:在严格模式下的定时器,this还是指向window,只有函数里this有变化

(4)不允许形参有重名

function dj(a,a) {  //严格模式下报错
    console.log(a+a);
}

(5)不允许在非函数代码块内声明函数

更多内容请见:MDN关于严格模式的描述

二、闭包

1.什么是闭包?

先复习一下:全局变量、局部变量和作用域链

闭包:能够访问另一个函数作用域中变量的函数。
原理:作用域链,当前作用域可以访问上级作用域中的变量

产生闭包的条件
1、函数套函数
2、内部函数访问外部函数局部变量,必须要访问了变量才会产生闭包

闭包就是将函数内部和函数外部连接起来的一座桥梁。

什么意思呢?举个例子:

函数inside访问了函数outside的作用域,那么inside函数就是一个闭包
function outside() {
    var n = 1;
    function inside() {
        console.log(n);  //1
    }
    inside();
}

outside();
console.log(n); //n is not defined

关于闭包的定义有些歧义,有的认为inside函数是闭包,有的认为outside里面的函数+环境共同构成闭包,这个不用太纠结。

2.闭包的作用

闭包的主要作用:延伸了变量的作用范围

我们可以借助闭包,实现从外部访问outside函数内部的变量:

function outside() {
    var n = 1;
    return function() {
        console.log(n); 
    }
}

let get_n = outside();
get_n();  //1  外部访问函数内部的变量

闭包还有个特点就是,一般来说outside函数调用完变量n就会销毁,但是闭包的话延伸了变量的作用范围outside函数调用完n不会立即销毁,等到get_n函数调用完,n才销毁,即函数作用域中的变量在函数执行结束之后不被销毁

不过这也导致闭包有个缺点:

由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。

3.闭包的一些应用

先看看什么是立即执行函数:

function fn(a) { console.log(a) }
fn(a);
===
(function(a) { console.log(a) })(a);

(1)点击li打印当前索引号(var)

复习:for循环中使用var的问题

创建一个立即执行函数,这样的话在里面添加点击事件就形成闭包,循环生成lis.length个立即执行函数,每个函数都拿到对应的i,这样的话函数调用完不会马上把当前i销毁,等到点击事件触发完后当前i才会销毁,这样就解决了问题(其实直接用let就可以了)

不过这样的缺点是四个立即执行函数,内存泄漏和内存溢出问题比较严重

//应用1:点击li打印当前索引号(用var声明)
for (var i = 0; i < lis.length; i++) {
    //创建一个立即执行函数,把i传进去
    (function (i) {
        lis[i].onclick = function() {
            console.log(i);
        }
    })(i);
}

(2)3秒后打印索引号(var)

和上面的一个意思,定义多个立即执行函数。
3秒后才访问变量i,那么i就不会立即被销毁,定时器结束调用后才销毁。

//应用2:3秒后打印索引号(用var声明)
for (var i = 0; i < lis.length; i++) {
    //创建一个立即执行函数,把i传进去
    (function (i) {
        setTimeout(() => {
            console.log(i);
        }, 3000);
    })(i);
}

(3)用闭包手撕防抖节流

还不会撕,先占个位

三、递归

1.什么是递归?

1、递归就是函数内部自己调用自己
2、递归函数的作用和循环差不多,就是无限套娃

递归很容易会发生栈溢出(不断调用不断开辟内存空间,函数放在堆里,函数的调用结果放在栈里,所以是栈溢出不是堆溢出),所以一定要加return才行

let num = 1;
function fn() {
    console.log('打印6句话');
    if (num === 6) {
        return;
    }
    num++;
    fn();
}
fn();

2.递归函数求阶乘

利用递归求1~n的阶乘
这个确实难想……好好理解理解代码吧。
4*cal(3) => 4*(3*cal(2)) => 4*(3*(2*cal(1))) => 4*(3*(2*1))

//利用递归求1~n的阶乘
function cal(n) {
    if(n===1) {
        return 1;
    }
    return n * cal(n-1);
}
console.log(cal(4));  //24

3.递归求斐波那契数列第几个数是谁

1、1、2、3、5、8、13、21、34……
这个也有点不太好想…………

//利用递归求斐波那契数列第几个数是谁(1,1,2,3,5,8,13,21...)
function fb(n) {
    if (n === 1 || n === 2) {
        return 1;
    }
    return fb(n - 1) + fb(n - 2)
}
console.log(fb(6));

执行过程:

fb(6) 
=> fb(5) + fb(4) 
=> (fb(4) + fb(3)) + (fb(3) + fb(2))
=> ((fb(3) + fb(2)) + (fb(2) + fb(1))) + ((fb(2) + fb(1)) + fb(2))
=> ((fb(2) + fb(1)) + 1) + (1 + 1)) + ((1 + 1) + 1)
=> 3 + 2 + 2 + 1

4.递归遍历数据

先模拟一套后台数据:

let data = [
    {
        id: 1,
        name:'家电',
        good: [
            {
                id: 11,
                gname: '冰箱'
            },
            {
                id: 12,
                gname: '洗衣机'
            }
        ]
    },
    {
        id: 2,
        name: '服饰'
    }
]

实现输入id号就返回对应的数据对象,怎么搞?

首先forEach遍历,如果是一级数据id直接输出该对象。
不是一级数据id就要看一下对象里有没有goods数组,有的话要递归调用getId,把goodsid传进去,再输出该对象。

function getId(data,id) {
    data.forEach(el => {
        if(el.id === id) {
            console.log(el);
        } else if(el.goods) {  //如果有goods数组再递归
            getId(el.goods, id); //递归调用传入good数组
        } 
    });
}
getId(data,12);

四、深拷贝和浅拷贝

1、浅拷贝只拷贝一层,对象级别只拷贝地址
2、深拷贝拷贝多层,每一级都会拷贝

1.浅拷贝

先定义两个对象

const obj = {
    name: 'zzy',
    age: 18,
    grade:{math: 100}
}
const copyObj = {}

把obj浅拷贝给copyObj ,有两种方式

//1.通过for...in实现浅拷贝
for(let k in obj) {
    console.log(k) //'name', 'age'
    copyObj[k] = obj[k];
}
console.log(copyObj);
//2.通过Object.assign(target, copywho)实现浅拷贝
Object.assign(copyObj,obj);
console.log(copyObj);

由于浅拷贝只拷贝一层,所以objgrade对象拷贝过来的是地址,如果copyObj对象中修改了grade.math,那么obj中的grade.math也会变。

2.手撕深拷贝

手撕深拷贝,利用递归实现

//利用递归手写深拷贝
function deepCopy(newObj, oldObj) {
    for (let k in oldObj) {
        //判断属性值属于哪种数据类型
        //1.如果是数组(判断数组要在对象前,因为数组也是对象)
        if(oldObj[k] instanceof Array) {
            newObj[k] = [];//赋值空,然后再把数组里的元素一个一个拷贝进来
            deepCopy(newObj[k], oldObj[k]); 
        }
        //2.如果是对象
        else if(oldObj[k] instanceof Object) {
            newObj[k] = {};//赋值空,然后再把对象里的属性一个一个拷贝进来
            deepCopy(newObj[k], oldObj[k]);
        }
        //3.如果是普通数据类型,直接浅拷贝
        else {
            newObj[k] = oldObj[k];
        }
    }
    return newObj;
}
deepCopy(copyObj, obj);
copyObj.grade.math = 99;
console.log(obj);  //math100
console.log(copyObj); //math99

递归是真tm恶心啊兄弟们

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12978.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AMD发布22.11.1驱动,支持《使命召唤:战区2.0》

他来了他来了&#xff0c;带着迷人的脚步走来了&#xff01; 《使命召唤&#xff1a;战区2.0》正式上线了。有Steam周榜三连冠的《使命召唤19》在前&#xff0c;《战区2.0》可以说是备受瞩目&#xff0c;免费大逃杀&#xff0c;谁不期待&#xff1f; &#xff08;图源自steam&…

一句话生成图片,FlagAI使用(附页面操作代码) | 机器学习

目录 前言 项目结构 页面交互调整 总结 前言 最近Text-To-Image是一个很火的话题&#xff0c;甚至更进一步的Text-To-Video话题度也在不断上升。最近看到一个开源项目FlagAI&#xff0c;是目前我觉着效果比较好的项目之一。安装操作简单&#xff0c;支持中英文&#xff0c;…

疫情防控管理系统

1、项目介绍 疫情防控管理系统拥有两种角色&#xff1a;管理员和用户 管理员&#xff1a;医护信息管理、物资管理、疫苗管理、疫站管理等 用户&#xff1a;登录注册、物资、疫苗、疫站查看 2、项目技术 后端框架&#xff1a; Servlet、mvc模式 前端技术&#xff1a;Bootst…

yolov5剪枝实战1: 论文及yolov5剪枝实战项目介绍

本系列博客介绍yolov5剪枝方法 1. 介绍 神经网络一般都存在过参数化(over-parameterized)的问题,存在冗余的神经元或权重,所以可以进行剪枝。 其实对网络可以针对不同的颗粒度进行剪枝,可以进行权重、神经元级别的剪枝,也可以基于channel, shape,filter以及layer级别的剪枝…

卷积神经网络基础

由于篇幅所限&#xff0c;本章将重点介绍计算机视觉的经典模型&#xff08;卷积神经网络&#xff09;和两个典型任务&#xff08;图像分类和目标检测&#xff09;。主要涵盖如下内容&#xff1a; 卷积神经网络&#xff1a;卷积神经网络&#xff08;Convolutional Neural Netwo…

Nginx知识汇总

一、Nginx的简介 nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器&#xff1b;同时也是一个IMAP、POP3、SMTP代理服务器&#xff1b;nginx可以作为一个HTTP服务器进行网站的发布处理&#xff0c;另外nginx可以作为反向代理进行负载均衡的实现。 二、Nginx的优…

基于微信小程序的沁园健身房预约管理系统设计与实现-计算机毕业设计源码+LW文档

小程序开发说明 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Mave…

[附源码]Python计算机毕业设计 楼盘销售管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

【Linux】第十二章 多线程(线程概念+线程控制)

&#x1f3c6;个人主页&#xff1a;企鹅不叫的博客 ​ &#x1f308;专栏 C语言初阶和进阶C项目Leetcode刷题初阶数据结构与算法C初阶和进阶《深入理解计算机操作系统》《高质量C/C编程》Linux ⭐️ 博主码云gitee链接&#xff1a;代码仓库地址 ⚡若有帮助可以【关注点赞收藏】…

UNet - 训练数据train

目录 1. train 训练数据 2. Loss 值 3. 完整代码 1. train 训练数据 训练的代码只是在之前图像分类的基础上做了一些更改&#xff0c;具体的可以看下面的文章 pytorch 搭建 LeNet 网络对 CIFAR-10 图片分类https://blog.csdn.net/qq_44886601/article/details/127498256 …

EventBridge 生态实践:融合 SLS 构建一体化日志服务

作者&#xff1a; 昶风 引言 阿里云日志服务 SLS 是一款优秀的日志服务产品&#xff0c;提供一站式地数据采集、加工、查询与分析、可视化、告警、消费与投递等服务。对于使用 SLS 的用户业务而言&#xff0c;SLS 上存储的日志信息反映着业务的运行状态&#xff0c;通过适当地…

2021年认证杯SPSSPRO杯数学建模D题(第一阶段)停车的策略全过程文档及程序

2021年认证杯SPSSPRO杯数学建模 D题 停车的策略 原题再现&#xff1a; 开车前往人流集中的目的地时&#xff0c;决定在何处停车经常是一个难题。是停在距离目的地较远的地方&#xff0c;因为那里的空余车位可能较多&#xff0c;然后再走很远的路&#xff1f;或者是否应该乐观…

【C语言】程序的翻译环境和执行环境

&#x1f6a9;write in front&#x1f6a9; &#x1f50e;大家好&#xff0c;我是謓泽&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f3c5;2021年度博客之星物联网与嵌入式开发TOP5&#xff5…

智慧博物馆解决方案-最新全套文件

智慧博物馆解决方案-最新全套文件一、建设背景二、思路架构三、解决方案建成5个方面1、集约化2、物联网接入3、大数据可视化分析4、室内室外地图集成5、可视化信息多元交互四、获取 - 智慧博物馆全套最新解决方案合集一、建设背景 博物馆是征集、典藏、陈列和研究代表自然和人…

【FME实战教程】002:FME完美实现CAD数据转shp案例教程(以三调土地利用现状数据为例)

FME完美实现CAD数据转shp案例教程&#xff08;以三调土地利用数据为例&#xff09; 文章目录1. cad数据预览2. 转换过程3. shp数据预览1. cad数据预览 2. 转换过程 &#xff08;1&#xff09;打开FME Desktop2020中文软件&#xff0c;点击【新建】。 &#xff08;2&#xff09…

【Spring】——2、使用@ComponentScan自动扫描组件并指定扫描规则

&#x1f4eb;作者简介&#xff1a;zhz小白 公众号&#xff1a;小白的Java进阶之路 专业技能&#xff1a; 1、Java基础&#xff0c;并精通多线程的开发&#xff0c;熟悉JVM原理 2、熟悉Java基础&#xff0c;并精通多线程的开发&#xff0c;熟悉JVM原理&#xff0c;具备⼀定的线…

微信小程序开发(九):使用扩展组件库

前端开发中离不开各种组件库&#xff0c;我最先接触的组件库还是Bootstrap&#xff0c;后来工作中又陆续使用了inoic、ng-zorro等各种不同的库。 在微信小程序开发中也有多种组件库&#xff0c;这里记录其中几种不同组件库的使用方法。 WeUI 这是微信官方推出的一款和微信原…

使用Python,Open3D对点云散点投影到面上并可视化,使用3种方法计算面的法向量及与平均法向量的夹角

使用Python&#xff0c;Open3D对点云散点投影到面上并可视化&#xff0c;使用3种方法计算面的法向量及与平均法向量的夹角 写这篇博客源于博友的提问&#xff0c;他坚定了我继续坚持学习的心&#xff0c;带给了我充实与快乐。 将介绍以下5部分&#xff1a; 随机生成点云点投影…

LaTeX学习笔记

LaTeX学习笔记 文章目录LaTeX学习笔记1. 开始的尝试2.文档类与宏包3.标题与章节4.标注5.列表6.对齐7.插入代码块8.绘制表格9.插入图片10.数学公式10.1.基础公式10.2.复杂公式10.3 常用符号11.参考文献冲鸭&#xff01;&#xff01;&#xff01; 1. 开始的尝试 先开始试一下一个…

MySQL数据库索引和事务详解

目录 前言&#xff1a; 索引 查看索引 创建索引 删除索引 索引使用 底层数据结构分析 事务 事务引出 MySQL设计事务 事务四大特性 小结&#xff1a; 前言&#xff1a; 数据库索引和事务的存在&#xff0c;对于数据库的一些性能有了显著提升。我们需掌握其底层的实现…