夯实基础,彻底掌握js的核心技术(三):堆栈内存及闭包详解

网友投稿 1056 2022-11-17

夯实基础,彻底掌握js的核心技术(三):堆栈内存及闭包详解

夯实基础,彻底掌握js的核心技术(三):堆栈内存及闭包详解

数据渲染机制及堆栈内存

1. 数据值操作机制

解析如下图:

栈内存:作用域

提供一个供js代码自上而下执行的环境(代码都是在栈中执行)由于基本数据类型值比较简单,它们都是直接在栈内存中开辟一个位置,把值直接存储进去的当栈内存被销毁,存储的那些基本值也都跟着被销毁了

堆内存:引用值对应的空间

存储引用类型值的(对象:键值堆 函数:代码字符串)当前堆内存释放销毁,那么这个引用值彻底没了堆内存的释放: 当堆内存没有被任何的变量或者其它东西所占用,浏览器会在空闲的时候,自主的进行内存回收,把所有不被占用的堆内存销毁掉(谷歌浏览器)(xxx= null,通过空对象指针null可以让原始变量(或者其它东西)谁都不指向,那么原有被占用的堆内存就没有被东西占用了,浏览器会销毁它)

2. 变量提升机制

什么事变量提升

var a = 12var b = a;b = 13;console.log(a);var ary1 = [12, 23];var ary2 = ary1;ary2.push(100);console.log(ary1)function sum() { var total = null; for(var i = 0; i< arguments.length; i++;) { var item = arguments[i]; item = parseFloat(item); !isNaN(item) ? total += item : null; } return total;}console.log(sum(12, 23, '34', 'AA'))

变量提升机制解析:

带var和不带的区别

以上例子说明:全局变量和window中的属性存在“映射机制”**不加var的本质是window的属性如下面例子:

console.log(a) // Uncaught ReferenceError: a is not definedconsole.log(window.a) // undefinedconsole.log('a' in window) // falsea = 12 // window.a = 12console.log(a) // 12console.log(window.a) // 12

var a = 12, b = 13; // 这样写b是带var的var a = b = 12; // 这样写b是不带var的

私有作用域中带var和不带var也有区别:

console.log(a, b) // undefined , undefinedvar a = 12, b = 12;function fn() { console.log(a, b) // undefined, 12 var a = b = 13 console.log(a, b) // 13 13}fn();console.log(a, b) // 12, 13

解析如下图:

作用域链的扩展:

function fn() { b= 13; console.log('b' in window) // true,在作用链查找的过程中,如果找到window也没有这个变量,相当于给 // 给window设置了一个属性b(window.b = 13) console.log(b)}console.log(b)

等号左边变量提升

/* * 变量提升: * var fn; 只对等号左边进行变量提升 **/ sum();fn(); // Uncaught TypeError: fn is not a function// 匿名函数之函数表达式var fn = function () { console.log(1)}// 普通函数function sum() { console.log(2)}

条件判断下的变量提升

在当前作用域下,不管条件是否成立都要进行变量提升

f= function () { return true;}; // window.f = ....g = function () { return false}; // window.g = ...~function() { /* * 变量提升: * function g; g是私有变量 */ if(g() && ([] == ![])) { // Uncaught TypeError: g is not a function [] == ![] => 0 == 0 // 把全局中的f进行修改 f= function () { return false }; function g() { return true; } }}()console.log(f());console.log(g());

/* * 全局下变量提升 * function fn*/console.log(fn) // undefinedif(1 === 1) { console.log(fn) function fn() { console.log('ok') }}console.log(fn) //函数本身

重名问题的处理

3. ES6中let不存在变量提升

不允许重复定义不存在变量提升

console.log(a) //Uncaught ReferenceError: a is not definedlet a = 12;console.log(window.a) // undefinedconsole.log(a) // 12//-------------let a = 10, b = 10let fn =function () { // console.log(a, b) //Uncaught ReferenceError: a is not defined let a = b = 20 console.log(a, b) // 20, 20}fn();console.log(a, b) // 10, 20//-------------let a = 12console.log(a) let a = 13 // Uncaught SyntaxError: Identifier 'a' has already been declaredconsole.log(a)

暂时性死区

基于let创建变量,会把大部分{}当作一个私有块级作用域(类似函数的私有作用域),在这里也是重新检测语法规范,看一下是否基于新语法创建的变量,如果是按照新语法规范来解析es6解决了浏览器的暂时性死区问题

闭包作用域(scope)

1. 区分私有变量和全局变量

在私有作用域中,只有以下两种情况是私有变量:

剩下的都不是自己私有变量,都需要基于作用域链的机制向上查找

解析如下图:

2. 查找上级作用域

当前函数执行,形成一个私有作用域A,A的上级作用域是谁,和它在哪执行的没有关系,和它在哪创建的有关系,在哪创建(定义)的,它的上级作用域就是谁

var a = 12function fn() { // arguments:实参集合,arguments.callee:函数本身fn console.log(a)}function sum() { var a = 120 fn(); // 12}sum();//-------var n = 10;function fn() { var n = 20; function f() { n++; console.log(n) } f() return f;}var x = fn(); //21x(); //22x(); //23console.log(n); // 10

3. 闭包及堆栈内存释放

js中的内存分为堆内存和栈内存堆内存:存储引用数据类型值(对象:键值对 函数: 代码字符串)栈内存:提供js代码执行的环境和存储基本类型数据【堆内存释放】让所引用的堆内存空间地址的变量赋值为null即可(没有变量占用这个堆内存了,浏览器会在空闲的时候把它释放)【栈内存释放】一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉(在栈内存中存储的值也都会释放掉),但是也有特殊不销毁的情况:

函数执行完成,当前形成的栈内存中,某些内容被栈内存以外的变量占用了,此时栈内存不能释放(一旦释放,外面找不到原有的内容了)。全局栈内存只有在页面关闭的时候才会被释放掉

如果当前栈内存没有释放,那么之前在栈内存中存储的基本值也不会释放,能够一直保存下来

var i = 1;function fn(i) { return function (n) { console.log(n+ (++i)); }}var f = fn(2); //先把fn执行(传递实参2),把fn执行的返回结果(return后面的值)赋值股ff(3) // 把返回的结果执行 =》 6fn(5)(6) //12 和上面两个步骤类似,都是把fn执行,都是先把fn执行,把fn执行的返回的结果再执行fn(7)(8) // 16f(4) //8//---------// 在和其它值进行运算的时候一些区别// i++ ;自身累加1(先拿原有值进行运算,运算结束后,本身累加)// i++; 自身累加1 (先自身累加1,拿累加后的结果进行运算)var k = 1;console.log(5+(k++), k) // 6, 2console.log(5+ (++k), k) //7, 2//--------

解析如下图:

4. 闭包之保护机制

闭包:函数执行形成一个私有的作用域,保护里面的私有变量不受外界的干扰,这种保护机制称之为“闭包”。市面上的开发者认为的闭包是:形成一个不销毁的私有作用域(私有栈内存)才是闭包。

// 闭包:柯理化函数function fn() {return function(){}}var f = fn()//闭包:惰性函数var utils = (function(){ return { }})()

真实项目中为保证js的性能(堆栈内存的性能优化),应该可能减少闭包的使用(不销毁的堆栈内存是耗性能的)闭包保护功能:

闭包具有“保护”作用:保护私有变量不受外界的干扰(在真实项目只能够,尤其是团队协作开发的时候,应该尽可能地减少全局变量的使用,防止相互之间的冲突(“全局变量污染”)),那么此时我们完全可以把自己这一部分内容封装到一个闭包中,让全局变量转换为私有变量。

jQuery方式:把需要暴露的方法抛到全局zepto这种方式:基于return把需要供外面使用的方法暴露出去

闭包具有“保护”作用:形成不销毁的栈内存,把一些值保存下来,方便后面的调取使用

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:什么是Docker并且它为什么这么受欢迎
下一篇:JDK8中新的日期时间工具类真的很好用,还不清楚的快进来看看吧,建议收藏
相关文章

 发表评论

暂时没有评论,来抢沙发吧~