js(深浅拷贝,节流防抖,this指向,改变this指向的方法)

一、深浅拷贝

1.基本数据类型和引用数据类型的区别:

      1. 基本数据类型的变量存储的是值

         引用数据类型的变量存储的是地址值

      2. 基本数据类型的变量存储的值在栈内存

          引用数据类型的变量存储的值在堆内存

      3. 基本数据类型的变量存储的是值和值之间相互不影响

         引用数据类型的变量存储的值和值,在同用 一个地址的情况,其中一个的值发生变化,另一个也变

2.  深浅拷贝之发生在引用数据类型之间。

      深拷贝: 拷贝的是值,源对象和拷贝的对象之间互不影响

      浅拷贝: 拷贝的是地址,源对象和拷贝的对象存在公用一个地址的情况,所以相互之间会收到影响

3.浅拷贝
方法一:Object.assign() 方法

用于将一个或多个源对象的可枚举属性复制到目标对象。它只会进行浅拷贝。

    const obj1 = {a: 1,b: {c: 2}};const obj2 = Object.assign({}, obj1);obj2.a = 2; // obj1.a 仍然是 1obj2.b.c = 3; // obj1.b.c 也变成 3console.log(obj1); // { a: 1, b: { c: 3 } }console.log(obj2); // { a: 2, b: { c: 3 } }
方法二:展开运算符...

使用展开运算符 ... 可以方便地创建一个对象的浅拷贝。

    const obj1 = {a: 1,b: {c: 2}};const obj2 = {...obj1 };obj2.a = 2; // obj1.a 仍然是 1obj2.b.c = 3; // obj1.b.c 也变成 3console.log(obj1); // { a: 1, b: { c: 3 } }console.log(obj2); // { a: 2, b: { c: 3 } }

方法:Object.create()

使用 Object.create() 可以创建一个新对象,新对象的原型指向指定的对象,但这并不是传统意义上的拷贝,而是基于原型链的一个新对象。

    const obj1 = {a: 1,b: {c: 2}};const obj2 = Object.create(obj1);obj2.a = 2; // obj1.a 仍然是 1obj2.b.c = 3; // obj1.b.c 也变成 3console.log(obj1); // { a: 1, b: { c: 3 } }console.log(obj2); // { a: 2 }

 

    //===================for=================================var arr = [12, [34, 56, 78], 543, 67, 78]var brr = []for (var i = 0; i < arr.length; i++) {brr.push(arr[i])}// console.log(brr);// 第一层是深拷贝brr[0] = 20;console.log(arr); // [12, [34, 56, 78], 67, 78]console.log(brr); // [20, [34, 56, 78], 67, 78]// 第二是浅拷贝brr[1][0] = 43console.log(arr);//[12, [43, 56, 78],, 67, 78]console.log(brr);// [12, [43, 56, 78],, 67, 78]// ===================arr.slice(0)===========================var arr = [12, [34, 56, 78], 543, 67, 78]var brr = arr.slice(0)// 第一层是深拷贝brr[0] = 20;console.log(arr); // [12, [34, 56, 78],, 67, 78]console.log(brr); // [20, [34, 56, 78],, 67, 78]// 第二是浅拷贝brr[1][0] = 43console.log(arr);//[12, [43, 56, 78],, 67, 78]console.log(brr);// [12, [43, 56, 78],, 67, 78]// ===================arr.concat()===========================var arr = [12, [34, 56, 78], 543, 67, 78]var brr = arr.concat()// 第一层是深拷贝brr[0] = 20;console.log(arr); // [12, [34, 56, 78],, 67, 78]console.log(brr); // [20, [34, 56, 78],, 67, 78]// 第二层是浅拷贝brr[1][0] = 43console.log(arr);//[12, [43, 56, 78],, 67, 78]console.log(brr);// [12, [43, 56, 78],, 67, 78]//--------------------------Array.from()----------------------//Array.from() 方法可以用于创建一个新数组实例,它会浅拷贝类数组对象或可迭代对象。const arr1 = [1, 2, 3, { a: 4 }];const arr2 = Array.from(arr1);arr2[0] = 0; // arr1[0] 仍然是 1arr2[3].a = 5; // arr1[3].a 也变成 5console.log(arr1); // [1, 2, 3, { a: 5 }]console.log(arr2); // [0, 2, 3, { a: 5 }]

直接赋值和浅拷贝的区别:

直接复制的方法,只要是对象都会相互影响,因为是直接拷贝对象栈里面的地址

浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响

4.深拷贝
方法一:递归

函数递归:如果一个函数在内部自己调用自己,那么这个函数就是递归函数

由于递归函数很容易发生栈溢出错误,所以需要加推出条件return

    let i = 0;function fn() {console.log(`调用${i} 次   `);if (i >= 6) {return}i++fn()}fn()

利用setTimeout实现setInterval效果

    function getTime() {document.querySelector('#box').innerHTML = new Date().toLocaleString()setTimeout(getTime, 1000)getTime()}getTime()
    const obj1 = {a: 1,b: {c: 2}};const obj2 = {};function deepCopy(newObj, oldObj) {for (let key in oldObj) {if ((oldObj[key]).instanceof Array) {newObj[key] = []deepCopy(newObj[key], oldObj[key])} else if ((oldObj[key]).instanceof Object) {newObj[key] = {}deepCopy(newObj[key], oldObj[key])} else {newObj[key] = oldObj[key]}}}deepCopy(obj2, obj1)obj1.b.c = 6console.log('obj2, obj1', obj2, obj1);
function deepClone(obj) {if (obj === null || typeof obj !== 'object') {return obj; // 基础情况,直接返回值}// 创建一个新对象const newObj = Array.isArray(obj) ? [] : {};// 递归拷贝每个属性for (const key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = deepClone(obj[key]);}}return newObj;
}

方法二:lodash

Lodash 简介 | Lodash中文文档 | Lodash中文网

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>var p = {name: "zs",age: 12,wife: {name: "zs的媳妇"}}var newP = _.cloneDeep(p);newP.wife.name = 'ls的媳妇'console.log(p);console.log(newP);var arr = [12, [34], 5, 67, 78, 8]var newArr = _.cloneDeep(arr);arr[1][0] = 43;console.log(newArr);console.log(arr);
</script>
方法三:JSON.parse(JSON.stringify(obj))
    var obj = { name: "zs", age: 18, wife: { name: "zs的wife", city: { name: '上海' } } }var obj1 = JSON.parse(JSON.stringify(obj))

二、节流(技能冷却)

节流:单位时间内,频繁触发事件,只执行一次

使用场景:鼠标移动mousemove,页面尺寸缩放resize,滚动条滚动scroll等

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #ededed;}</style>
</head>
<body><div id="box"></div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>const box = document.querySelector('#box')let i = 1;function mouseMove() {box.innerHTML = i++}box.addEventListener('mousemove', _.throttle(mouseMove, 3000))
</script>

核心思路:

a.声明一个定时器变量

b.当鼠标每次滑动都先判断是否有定时器,如果有定时器则不开开启新定时器

c.如果没有定时器则开启定时器,记得存到变量里面

定时器里面调用执行的函数

定时器里面要把定时器清空

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #ededed;}</style>
</head>
<body><div id="box"></div>
</body>
</html>
<script>const box = document.querySelector('#box')let i = 1;function mouseMove() {box.innerHTML = i++}box.addEventListener('mousemove', throttle(mouseMove, 3000))function throttle(fn, t) {let timer = null;return function() {if (!timer) {timer = setTimeout(() => {fn()clearTimeout(timer)timer = null}, t)}}}// let timer = null;// timer = setTimeout(() => {//     clearTimeout(timer)//     console.log(timer)// }, 1000)//setTimeout中无法清除定时器,因为定时器还在运行
</script>

三、防抖(回城)

防抖:单位时间内,频繁触发事件,只执行最后一次,只要被打断就需要重来

使用场景:搜索框搜索输入,手机号、邮箱验证输入检测

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #ededed;}</style>
</head>
<body><div id="box"></div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>const box = document.querySelector('#box')let i = 1;function mouseMove() {box.innerHTML = i++}box.addEventListener('mousemove', _.debounce(mouseMove, 3000))
</script>

 核心思路:

a.声明一个定时器变量

b.当鼠标每次滑动都先判断是否有定时器,如果有定时器则清除前面的定时器

c.如果没有定时器则开启定时器,记得存到变量里面

d.定时器里面调用执行的函数

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #ededed;}</style>
</head>
<body><div id="box"></div>
</body>
</html>
<script>const box = document.querySelector('#box')let i = 1;function mouseMove() {box.innerHTML = i++}box.addEventListener('mousemove', debounce(mouseMove, 3000))function debounce(fn, t) {let timer = null;return function() {if (timer) {clearTimeout(timer)}timer = setTimeout(() => {fn()}, t)}}// debounce(mouseMove, 3000)调用函数拿到return结果// debounce(mouseMove, 3000)=function(){}
</script>

性能优化说明使用场景
节流单位时间内,频繁触发事件,只执行一次鼠标移动mousemove,页面尺寸缩放resize,滚动条滚动scroll等
防抖单位时间内,频繁触发事件,只执行最后一次搜索框搜索输入,手机号、邮箱验证输入检测

四、节流案例

页面打开,可以记录上一次视频播放的位置

思路:

在ontimeupdate事件触发的时候,每隔1秒,就记录当前时间到本地存储

下次打开页面,onloadeddata事件触发,就可以从本地存储取出时间,让视频从取出的时间播放,如果没有就默认0s

获取当前时间video.currentTime

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #ededed;}</style>
</head>
<body><div id="box"><video src="https://v.itheima.net/LapADhV6.mp4" controls autoplay loop muted preload="auto" width="640" height="360"></video></div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>//ontimeupdate事件在视频/音频当前的播放位置发生改变时触发//onloadeddata事件在当前帧的数据加载完成且没有足够的数据播放视频/音频的下一帧时触发const video = document.querySelector('video')video.ontimeupdate = _.throttle(() => {console.log(video.currentTime);localStorage.setItem('currentTime', video.currentTime)}, 1000)video.onloadeddata = () => {video.currentTime = localStorage.getItem('currentTime') || 0}
</script>

五、this指向

普通函数:谁调用this的值指向谁

1.全局函数 === window
2.回调函数 ===window

回调函数: 当一个函数作为另一个函数的参数, 那么这个函数就叫回调函数

    console.log(this); //windowfunction fn() {console.log(this); //window}fn()setTimeout(function() {console.log(this); //window}, 1000)
​3.在对象方法中 ===对象本身
4.事件中的 ===绑定事件的事件源  
    document.querySelector('button').addEventListener('click', function() {console.log(this); //<button>按钮</button> ,指向button})const obj = {sayHi: function() {console.log(this);//{sayHi: ƒ},指向obj}}obj.sayHi()
​5.构造函数中 === new出来的对象 ​
6.原型对象上对应的方法体内的this ===new出来的对象  
    let a;let b;function Star(name, age, sex) {a = this;this.name = name;this.age = age;}const ldh = new Star('ldh', 55)console.log(a === ldh);//true//构造函数里面的 this就是实例对象Star.prototype.sing = function() {b = this;console.log('唱歌');};ldh.sing()console.log(b === ldh);//true
7.箭头函数===没有this 指向上级作用域

箭头函数:箭头函数中不存在this,箭头函数会默认绑定外层this的值,this引用的就是最近作用域中的this,向外层作用域中,一层一层查找this,直到有this的定义

    const obj = {sayHi: () => {console.log(this); //window}}obj.sayHi()document.querySelector('button').addEventListener('click', () => {console.log(this); //window})

六、修改this的指向

有3个方法可以动态指定普通函数中的this指向

call(),apply(),bind()

1.fun.call(thisArg,arg1,arg2,...)

thisArg是在fun函数运行时指定的this值

返回值就是函数的返回值,因为它就是调用函数

2.fun.apply(thisArg,[arg1,arg2,...])
    const obj = {name: 'zs'}function fn(x, y) {console.log(this); //windowconsole.log(x + y);}fn()//调用函数,改变this指向fn.apply(obj, [1, 2])
    const arr = [11, 22, 33, 44, 55]const max = Math.max.apply(Math, arr)console.log('max', max);
3.fun.bind(thisArg,arg1,arg2,...)

bind()方法不会调用函数,

能改变函数内部的this指向

返回值是个函数,但是这个里面的this是更改过的this

    const obj = {name: 'zs'}function fn(x, y) {console.log(this); //windowconsole.log(x + y);}fn()//不会调用函数,能改变this指向//返回值是个函数,但是这个函数里面的this是更改过的thisconst fun = fn.bind(obj)fun()

案例:点击按钮禁用,2秒后开启 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button>发送短信</button>
</body>
</html>
<script>const btn = document.querySelector('button')btn.addEventListener('click', function() {this.disabled = truesetTimeout(function() {//在这个普通函数里,我们要this的指向由原来的window改为btn,可以使用箭头函数,也可以使用bindthis.disabled = false}.bind(btn), 2000)})
</script>
 4.总结

call,apply,bind

相同点:都可以改变this的指向

区别点:

call和apply会调用函数,并且改变函数内部this的指向。

call和apply传递的参数不同,call传递多个参数,apply以数组的形式传递多个参数

bind不会调用函数,而是返回了一个this指向改变后的函数,需要调用这个函数。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

矩阵基础知识

矩阵定义 矩阵的定义 1.矩阵是由一组数按照矩形排列而成的数表。矩阵通常用大写字母表示&#xff0c;例如 AA、BB 等。矩阵中的每个数称为矩阵的元素或元。 一个 mn的矩阵 AA 可以表示为&#xff1a; 其中 aij表示矩阵 A中第i行第j列的元素。 矩阵的维度 1.矩阵的维度由它…

【多线程和高并发】多线程和高并发提纲

文章目录 多线程(多线程问题的)三大源头两个主要问题两大解决方案 高并发问题解决方案 对多线程和高并发相关问题整理了一个简单的提纲。 通过这个提纲&#xff0c;足够引出对并发编程中大部分问题的讨论~ 多线程 (多线程问题的)三大源头 线程并发执行带来的原子性问题。这是…

去梯之言:招聘行业运作的秘密——之找到一份工作

一、前言 招聘行业是一个水很深的行当。不过&#xff0c;尽管它很复杂&#xff0c;了解该行业的工作方式还是很重要的&#xff0c;这样你就可以在这片波涛汹涌的水域中平安航行&#xff0c;获得自己心仪的软件开发职位。反过来&#xff0c;如果你对这个波谲云诡的行业一无所知&…

接口测试(四)jmeter——文件上传

一、文件上传&#xff08;注&#xff1a;示例仅供参考模仿&#xff09; 1. 添加【HTTP信息头管理器】&#xff0c;配置【HTTP信息头管理器】如下&#xff1a; 2. 添加【HTTP请求默认值】&#xff0c;配置【HTTP请求默认值】如下&#xff1a; 3. 添加【HTTP请求】&#xff0…

window7虚拟机VMware与主机共享文件

文件管理器》计算机网络右键》属性》高级共享设置——全部启用 新建文件夹》右键》属性》共享》选择可以共享的用户——我这里选的是所有用户 点击高级共享》权限》保存设置——设置文件权限 文件管理器》计算机网络》右键》属性》————查看虚拟机计算机名称 主机访问 主机…

GIS常见前端开发框架

#1024程序员节&#xff5c;征文# 伴随GIS的发展&#xff0c;陆续出现了众多开源地图框架&#xff0c;这些地图框架与众多行业应用融合&#xff0c;极大地拓展了GIS的生命力&#xff0c;这里介绍几个常见的GIS前端开发框架&#xff0c;排名不分先后。 1.Leaflet https://leafl…

android 微信分享报:签名不对,请检查签名是否与开发平台签名一致的解决

1、微信分享会检查签名与开发平台的签名是否一致&#xff1a; 基本信息 | 微信开放文档 官方文档 下载签名工具&#xff0c;并且&#xff0c;将包名输入&#xff0c;然后点击生成&#xff0c;得到这个一串字符串。 2、到开发平台中&#xff1a;微信开放平台 登录&#xff0c;…

Vue2、Element中实现Enter模拟Tab,实现切换下一个框的效果

目录 &#x1f4c3;前序 &#x1f449;开发历程 &#x1f4bb;实际代码 &#x1f4fd;实现效果图 前序 在几乎所有的浏览器中&#xff0c;都具备通过 Tab 键来切换焦点的功能。然而&#xff0c;有些用户提出了强烈要求&#xff0c;希望能够增加通过 Enter 键…

批量合并PDF 文件的 5 大解决方案

PDF 可以将一个、两个、三个甚至更多的记录封装在一起&#xff0c;以显示完整的信息和用于逻辑和交互式结构化的不同元素。由于 PDF 可以提出多层结构&#xff0c;因此当用户知道如何最大化这种格式时&#xff0c;将所有文件组织到其中非常有效。正如许多经验丰富的用户和 PDF …

selenium案例——爬取哔哩哔哩排行榜

案例需求&#xff1a; 1.使用selenium自动化爬虫爬取哔哩哔哩排行榜中舞蹈类的数据&#xff08;包括视频标题、up主、播放量和评论量&#xff09; 2.利用bs4进行数据解析和提取 3.将爬取的数据保存在本地json文件中 4.保存在excel文件中 分析&#xff1a; 1.请求url地址&…

03 springboot-国际化

Spring Boot 提供了很好的国际化支持&#xff0c;可以轻松地实现中英文国际化。 项目创建&#xff0c;及其springboot系列相关知识点详见&#xff1a;springboot系列 springboot系列&#xff0c;最近持续更新中&#xff0c;如需要请关注 如果你觉得我分享的内容或者我的努力对…

2024年软件设计师中级(软考中级)详细笔记【11】知识产权基础知识(分值2~3分)

目录 前言第11章 知识产权基础知识【2-3分】11.1 标准化基础知识11.2 知识产权基础知识11.2.2 计算机软件著作权11.2.3 计算机软件的商业秘密权11.2.4 专利权概述习题 结语 前言 在备考软件设计师中级考试的过程中&#xff0c;我遇到了些许挑战&#xff0c;也收获了宝贵的经验…

基于django的个人相册日记管理系统

你是否还在为毕业设计苦思冥想&#xff0c;不知道怎么选择一个合适又实用的技术项目&#xff1f;今天给大家介绍一款功能全面的Django项目——个人相册日记管理系统&#xff0c;堪称毕业设计的完美选择&#xff01; 首先&#xff0c;这不是简单的相册或日记本&#xff0c;而是…

苍穹外卖05

redis 1. 启动redis .\redis-server.exe redis.windows.conf 2. 连接redis到客户端(这里我们使用ARDM图形化工具) 新建连接 一旦建立好后就永久直接可用(和mysql一个道理) 连接成功界面

【华为HCIP实战课程十八】OSPF的外部路由类型,网络工程师

一、外部路由类型: 上节讲的外部路由类型,无关乎COST大小,OSPF外部路由类型1优先于外部路由类型2 二、转发地址实验拓扑 我们再SW3/R5/R6三台设备运行RIP,SW3即运行RIP又运行OSPF SW3配置rip [SW3-rip-1]ver 2 [SW3-rip-1]network 10.0.0.0 AR5去掉ospf配置和AR6配置rip…

win10中mysql数据库binlog恢复

win10中mysql数据库binlog恢复 昨天有朋友江湖救急&#xff0c;说测试库里的表不小心删除更新了数据。这里也复习下binlog数据恢复&#xff0c;当然需要一定的条件&#xff1a;首先mysql开启binlog&#xff0c;然后每天需要备份对应的数据库 1 单库单表准备 在恢复数据前&am…

使用Python和Matplotlib模拟3D海浪动画

使用Python和Matplotlib模拟3D海浪动画 在计算机图形学和动画领域&#xff0c;模拟逼真的海洋表面一直是一个具有挑战性的问题。本文将介绍如何使用Python的Matplotlib库和Gerstner波浪模型&#xff0c;创建一个动态的3D海浪动画。通过叠加多个波浪&#xff0c;我们可以生成复…

vim的使用方法

常见的命令可参考&#xff1a; Linux vi/vim | 菜鸟教程​www.runoob.com/linux/linux-vim.html​编辑https://link.zhihu.com/?targethttps%3A//www.runoob.com/linux/linux-vim.html 1. vim的工作模式 vi/vim 共分为三种模式&#xff0c;命令模式、编辑输入模式和末行&am…

高薪、高含金量、高性价比的“三高”证书——PMP证书

24年感觉什么都不好做&#xff0c;经济大环境也不太好&#xff0c;工作也卷&#xff0c;裁员降薪&#xff0c;为什么有的人没有危机&#xff0c;不降反增了呢&#xff1f;古语云往往越是危机的时候&#xff0c;越是机会多的时候&#xff0c;今天分享一个高薪、高含金量、高性 如…

关于写“查看IT设备详细信息”接口的理解

这两个星期一直在做关于IT资产管理相关的内容。这个内容大概就建立三张表&#xff0c;然后对三张表进行操作。一般情况下&#xff0c;对一张表也就那么几种操作&#xff1a;增删改查&#xff0c;导入导出。这里我说了6个操作&#xff0c;那就代表要写6个接口。这6个接口就是最常…