弄一个网站,泰州住房和城乡建设网站,核工业南京建设集团有限公司,做淘宝客网站需要多大空间详解栈在前端中的应用一、栈是什么二、栈的应用场景三、前端与栈#xff1a;深拷贝与浅拷贝1、JS数据类型#xff08;1#xff09;js数据类型的分类#xff08;2#xff09;js数据类型的定义和存储方式#xff08;3#xff09;js数据类型的判断方式2、深究浅拷贝和深拷贝…
详解栈在前端中的应用一、栈是什么二、栈的应用场景三、前端与栈深拷贝与浅拷贝1、JS数据类型1js数据类型的分类2js数据类型的定义和存储方式3js数据类型的判断方式2、深究浅拷贝和深拷贝1浅拷贝2深拷贝四、前端与栈函数调用堆栈五、写在最后栈 在日常生活中的应用非常广泛比如我们最熟悉不过的十进制转二进制、迷宫求解等等问题。同时它在前端中的应用也非常广泛很多小伙伴都会误以为
栈 在前端中的应用很少但殊不知的是我们写的每一个程序基本上都会用到
栈 这个数据结构。比如函数调用堆栈、数据的深拷贝和浅拷贝……。所以呢对于一个前端工程师来说 栈 结构是一个必学的知识点。在接下来的这篇文章中将讲解关于 栈 在前端中的应用。
一、栈是什么
栈是一种只能在表的一端栈顶进行插入和删除运算的线性表只能在栈顶运算且访问结点时依照后进先出 (LIFO) 或先进后出 (FILO) 的原则。
二、栈的应用场景
需要后进先出的场景比如十进制转二进制、迷宫求解、马踏棋盘、判断字符串是否有效、函数调用堆栈……。
三、前端与栈深拷贝与浅拷贝
1、JS数据类型
谈到堆栈我们需要先来了解一下关于 js 的两种数据类型。
1js数据类型的分类
首先JavaScript中的数据类型分为基本数据类型和引用数据类型。
了解完分类以后相信很多小伙伴心里有一个疑惑这两个数据类型是什么呢且在内存中是存放在哪里呢
2js数据类型的定义和存储方式
基本数据类型
基本数据类型是指 Numer 、 Boolean 、 String 、 null 、 undefined 、 SymbolES6新增的 、 BigIntES2020 等值它们在内存中都是存储在 栈 中的即直接访问该变量就可以得到存储在 栈 中的对应该变量的值。
若将一个变量的值赋值给另一个变量则这两个变量在内存中是独立的修改其中任意一个变量的值不会影响另一个变量。这就是基本数据类型。
引用数据类型
那引用数据类型呢是指 Object 、 Array 、 Function 等值他们在内存中是存在于 栈和堆 当中的即我们要访问到引用类型的值时需要先访问到该变量在 栈 中的地址这个地址指向堆中的值然后再通过这个地址访问到存放在 堆 中的数据。这就是引用数据类型。
这样说可能有点抽象让我们用一张图来理解一下。 从上图中可以看到 name 和 age 的值都是基本数据类型所以他们指向程序中 栈 的位置。而 like 是数组类型也就是引用数据类型所以在 栈 中它先存放了一个 like 的地址之后再把 like 对应的值存放到 堆 当中。
了解完数据类型和其存储方式后在面试中还有可能被问到如何判断某一个数据的类型是什么什么意思呢比如说给你一个数字 7 需要你来判断它是什么我们都知道它是Number类型但很多时候止步于如何做才能判断它是一个Number类型。接下来将详细介绍三种判断数据类型的方法。
3js数据类型的判断方式
常用判断方式typeof、instanceof、
1typeof
定义返回数据类型的字符串表达小写
用法typeof 变量
可以判断
undefined / 数值 / 字符串 / 布尔值 / function 返回 undefined / number / string / boolean / function null 、 object 与 array null、array、object都会返回 object
以下给出代码演示
script typetext/javascriptconsole.log(typeof Tony); // 返回 string console.log(typeof 5.01); // 返回 numberconsole.log(typeof false); // 返回 booleanconsole.log(typeof undefined); // 返回 undefinedconsole.log(typeof null); // 返回 objectconsole.log(typeof [1,2,3,4]); // 返回 objectconsole.log(typeof {name:John, age:34}); // 返回 object
/script2instanceof
定义判断对象的具体类型
用法b instanceof A → b是否是A的实例对象
可以判断 专门用来判断对象数据的类型: Object , Array 与 Function 判断 String Number Boolean 这三种类型的数据时直接赋值为 false 调用构造函数创建的数据为 true
以下给出代码演示
script typetext/javascriptlet str new String(hello world) //console.log(str instanceof String); → truestr hello world //console.log(str instanceof String); → falselet num new Number(44) //console.log(num instanceof Number); → truenum 44 //console.log(num instanceof Number); → falselet bool new Boolean(true) //console.log(bool instanceof Boolean); → truebool true //console.log(bool instanceof Boolean); → false/scriptscript typetext/javascriptlet items []; let object {}; function reflect(value) {return value; } console.log(items instanceof Array); // true console.log(items instanceof Object); // true console.log(object instanceof Object); // true console.log(object instanceof Array); // false console.log(reflect instanceof Function); // true console.log(reflect instanceof Object); // true
/script3
可以判断undefinednull
以下给出代码演示
script typetext/javascriptlet str;console.log(typeof str, str undefined); //undefined, truelet str2 null;console.log(typeof str2, str2 null); // object, true/script讲到这里我们了解了js的两种数据类型以及两种数据类型相关的存储方式和判断方式。那么接下来将讲解他们在前端中常见的应用深拷贝和浅拷贝。
2、深究浅拷贝和深拷贝
1浅拷贝
1定义
所谓浅拷贝就是一个变量赋值给另一个变量其中一个变量的值改变则两个变量的值都变了即对于浅拷贝来说是数据在拷贝后新拷贝的对象内部 仍然有一部分数据 会随着源对象的变化而变化。
2代码演示
// 浅拷贝-分析
function shallowCopy(obj){let copyObj {};for(let i in obj){copyObj[i] obj[i];}return copyObj;
}// 浅拷贝-实例
let a {name: 张三,age: 19,like: [打篮球, 唱歌, 跳舞]
}//将a拷贝给b
let b shallowCopy(a);a.name 李四;
a.like[0] 打乒乓球;
console.log(a);
/*
*{name: 李四,age: 19,like: [打乒乓球, 唱歌, 跳舞]}
*/
console.log(b);
/*
*{name: 张三,age: 19,like: [打乒乓球, 唱歌, 跳舞]}
*/3图例
从上面中的代码可以看到我们明明把 a 对象拷贝给 b 了但是 b 最终打印出来的结果部分数据不变部分数据却变了。这个时候很多小伙伴就很疑惑了这究竟是为什么呢
我们回顾上面所说到的关于 引用数据类型 的知识点上述代码中的 b 中的 like 是一个数组也就是引用数据类型。我们都知道引用数据类型的数据是存放于 栈和堆 当中的所以上述中的 like 数组我们将它视为一个地址这个地址存放于 栈 当中同时这个地址里面的数据就指向于 堆 当中。我们来看一下图例。 从上图中可以看到当对 a 中 like 的数据进行改变时它对应的数据在 堆 中改变。而 b 拷贝后的 like 地址所指向的数据也是跟 a 一样在 堆 中的位置。也就是说a 和 b 中的 like 地址它们的数据指向 堆 中的同一个位置所以 b 在拷贝完数据以后部分数据会随着 a 的变化而变化。这就是浅拷贝。
讲完浅拷贝接下来来了解深拷贝。
2深拷贝
1定义深拷贝就是新拷贝的对象内部所有数据都是 独立存在 的不会随着源对象的改变而改变。
2深拷贝有两种方式递归拷贝和利用 JSON 函数进行深拷贝。
递归拷贝的实现原理是对变量中的每个元素进行获取若遇到基本类型值直接获取若遇到引用类型值则继续对该值内部的每个元素进行获取。JSON深拷贝的实现原理是将变量的值转为字符串形式然后再转化为对象赋值给新的变量。
3局限性深拷贝的局限性在于会忽略undefined不能序列化函数不能解决循环引用的对象。
4代码演示
// 深拷贝-递归函数方法分析
function deepCopy(obj){// 判断是否为引用数据类型if(typeof obj object){let result obj.constructor Array ? [] : {};for(let i in obj){result[i] typeof obj[i] object ? deepCopy(obj[i]) : obj[i];}return result;}// 为基本数据类型直接赋值返回else{return obj;}
}// 深拷贝-递归函数方法实例
let c {name:张三,age:12,like:[打篮球,打羽毛球,打太极]
}let d deepCopy(c);c.name 李四;
c.like[0] 打乒乓球;
console.log(c);
/*
*{name: 李四,age: 19,like: [打乒乓球, 打羽毛球, 打太极]}
*/
console.log(d);
/*
*{name: 张三,age: 19,like: [打篮球, 打羽毛球, 打太极]}
*/// 深拷贝-JSON函数方法实例
let c {name: 张三,age: 19,like:[打篮球, 唱歌, 跳舞]
}let d JSON.parse(JSON.stringify(c));// 注意 JSON函数做深度拷贝时不能拷贝正则表达式Date方法函数等c.name 李四;
c.like[0] 打乒乓球;console.log(c);
/*
*{name: 李四,age: 19,like: [打乒乓球, 唱歌, 跳舞]}
*/
console.log(d);
/*
*{name: 张三,age: 19,like: [打篮球, 唱歌, 跳舞]}
*/从上述代码中可以看到深拷贝后的数据各自都是独立存在的不会随着源对象的变化而变化这就是深拷贝。不过值得注意的是在我们平常的开发中用的更多的是递归函数来进行深拷贝原因在于递归函数方法的灵活性会更强一点。而 JSON 函数方法有很多局限性在做深度拷贝时不能拷贝正则表达式、Date、方法函数等。
四、前端与栈函数调用堆栈
在我们平常的开发中经常会写很多函数那函数在执行过程中其实就是一个调用堆栈。接下来我们用一段代码来演示。
const func1 () {func2();console.log(3);
}const func2 () {func3();console.log(4);
}const func3 () {console.log(5);
}func1(); //5 4 3看到这里很多小伙伴心中可能已经在构思整段代码的执行顺序是什么样的。接下来用一张图来展示。 我们都知道 JavaScript 的执行环境是单线程的。所谓单线程是指一次只能完成一个任务如果有多个任务就必须排队只有当前面一个任务完成时才能执行后面一个任务以此类推。上图中所演示的即每调用一个函数如果里面还有新的函数那么就先把它放到调用堆栈里等到所有任务都放满以后开始依次执行。
而函数调用堆栈是一个典型的栈的数据结构遵循后进先出原则当 func1 func2 func3 依次放进调用栈后 遵循后进先出原则 那么 func3 函数的内容会先被执行之后是 func2 最后是 func1 。这就是函数调用堆栈。
五、写在最后
栈在前端中的应用就讲到这里啦栈在我们平常的开发中无处不在我们写的每一个程序基本上都会用到函数调用堆栈。且在前端的面试中面试官也很喜欢问深拷贝和浅拷贝大家可以对这块知识多回顾多实践。
如果有不理解或者有误的地方也欢迎私聊我或加我微信指正~ 公众号星期一研究室微信MondayLaboratory 创作不易如果这篇文章对你有用记得点个 Star 哦~