当前位置: 首页 > Web前端 > HTML

一篇文章带你了解JavaScript中的变量、作用域和内存问题

时间:2023-04-02 16:37:50 HTML

作者|来源|DadaFront-endBistro是一个引用类型值。基本类型值指的是一个简单的数据段。引用类型值可以由多个值组成。对象引用类型的值是存储在内存中的对象。JavaScript不允许直接操作对象的内存空间。其实就是操作对象的引用。而不是实际的对象。vardada=newObject();undefinedddada.name="dada";"dada"console.log(dada.name);VM158:1dadaundefinedvarda1="da1";undefinedda1.age=12;12console.log(da1.age);VM272:1给undefinedundefined基本类型的值添加属性是没有用的。仅对动态添加属性到引用类型的值有用。2复制变量值是将基本类型值和引用类型值从一个变量复制到另一个变量varda1=12;varda2=da1;da1中保存的值为12,当使用da1的值初始化da2时,da2也保存了值12,但d2中的值12和da1中的值12是完全独立的。这两个变量可以相互独立地参与任何操作。将引用类型的值从一个变量复制到另一个变量:引用类型的值实际上是一个指针,指向堆中存储的一个对象,引用类型的副本会指向同一个对象,所以更改其中一个变量,另一个兄弟变量也会受到影响。varda3=newObject();varda4=da3;da3.name="dada";console.log(da4.name);da3和da4指向同一个对象,da3加上name属性后,da4访问这个属性,因为两个变量都指向同一个对象,所以输出的是dada。3参数传递:在JavaScript中,所有函数的参数都是按值传递的。参数传值的意思和复制是一样的,把函数外的值传给函数内。函数addNum(num){num=num+1;返回num;}varda5=12;varresult=addNum(da5);控制台日志(da5);控制台日志(结果);函数addNum有一个参数num,这个参数其实是函数的一个局部变量。调用这个函数,变量da5作为参数传递给这个函数,这个变量的值为12,所以参数num为12,在这个addNum()函数中使用。functionsetName(obj){obj.name="dada";}varda6=newObject();setName(da6);console.log(da6.name);检测类型:typeof运算符用于检测一个变量是否为基本数据类型。如果变量的值是对象或null,则typeof运算符返回对象。varda7="dada";varda8=12;varda9;varda10=null;varda11=newObject();console.log(typeofda7);console.log(typeofda8);console.log(typeofda9);console.log(typeofda10);console.log(typeofda11);instanceof运算符是做什么用的?确定它是什么类型的对象。//前提是先定义personconsole.log(personinstanceofObject);console.log(personinstanceofArray);console.log(personinstanceofRegExp);注意所有引用类型的值都是Object的实例,所以检查引用类型的instanceof运算符对值和Object的构造函数都返回true。instanceof运算符检查基本类型的值并返回false。因为instanceof检测它是什么类型的对象。4作用域:当代码在一个环境中执行时,会创建一个变量对象的作用域链。这个作用域链的目的是确保所有有权访问执行环境的变量和函数的有序访问。全局执行环境的变量对象是作用域链中的最后一个对象。标识符解析是沿着作用域链逐级搜索标识符的过程。varda12="dada"functionchangeDa(){if(da12==="dada"){da12="da";}else{da12="da1";}}changeDa();console.log(da12);函数changeDa()的作用域链包含两个对象:它自己的变量对象,和全局环境的变量对象。它自己定义的参数对象varda12="dada"functionchangeDa(){varanotherDa="dadada";函数daDa(){vartempDa=anotherDa;另一个Da=da12;da12=tempDa;//可以访问tempDa,anotherDa,da12}//只能访问da12,anotherDadaDa();}//只能访问da12;改变大();分析执行环境,有3个,一个是全局环境,一个是changeDa()的局部环境,一个是daDa()的局部环境。全局环境中有一个变量da12,还有一个函数changeDa()。changeDa()的局部环境中有什么?一个变量anotherDa,一个名为daDa()的函数。该函数可以访问全局变量中的da12。daDa()的本地环境是什么?一个变量tempDa,只能在此环境中访问。changeDa()的全局环境和局部环境都不能访问tempDa。为什么内部daDa()可以访问其他两个环境中的所有变量?因为那是他们两个的环境是它的父执行环境。内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境中的任何变量和函数。内部环境可以向上搜索作用域链,检查变量和函数名称,但不能向下搜索作用域链进入另一个环境。对于daDa()函数,作用域链包含3个对象:daDa()的变量对象、changeDa()的变量对象、全局变量对象。过程:在daDa()函数的局部环境中,首先会在自己的变量对象中查找变量和函数名,如果找不到,则向上查找上层的作用域链。对于changDa()中的环境:包含两个对象:一个是自己的变量对象,一个是全局变量对象。也就是说,它无法访问daDa()函数的本地环境。5执行环境有两种:一种是全局范围,一种是局部范围。怎么理解trycatch扩展了作用域链呢?with语句和trycatch都可以扩展作用域链。with比较容易理解,一般会有性能问题,所以不推荐使用trycatch。捕获到Error对象时是否会打开一个新的作用域?或者catch的花括号是一个可以访问错误对象的块级作用域?try中的代码捕捉到错误后,异常对象会被压入一个变量对象中,放在作用域的头部。在catch代码块内部,函数的所有局部变量都会放在第二个作用域对象中,当catch中的代码执行完毕后,当前作用域会立即销毁。什么是扩展作用域链执行环境(变量对象可以描述为它的衍生物),作用域,作用域链作用域:函数当前的执行环境。作用域链:由执行环境产生的变量对象组成。作用域链是为了保证函数在执行时能够正确访问到需要的变量和函数。作用域链的最外层是全局作用域vari=0;functiondada(){console.log(i);}undefinedddada();VM656:30undefine函数中没有i,但是调用这个函数的时候会返回0,为什么?这就是函数作用域链所做的。扩展一:trycatch(function(window){try{throwError("Anerroroccurred");}catch(e){alert(e);//alert("Error:Anerroroccurred")}console.log(e);//未定义})(窗口);在执行catch语句块时,JavaScript会自动将其执行环境添加到作用域链中,但在语句块执行完毕后,会自动将执行环境(变量对象)移除。alert(e)==alert("错误:发生错误");console.log(e)==undefined;IE结果:alert(e)=>alert("Error:发生错误");console.log(e)=>objectError:Anerroroccurred{description:"Anerroroccurred",message:"Anerroroccurred",name:"Error"}扩展2:withfunctionda(){console.log(location.href);}functionda(){with(location){console.log(href);}}两种方法是等价的:前提是非严格模式,因为严格模式不支持with方法。扩展作用域的表现什么是作用域链?我的理解是,根据内部函数可以访问外部函数变量的机制,通过链式搜索来判断哪些数据可以被内部函数访问。想要了解js是如何链式运行的,首先要了解js的执行环境。每个函数在运行的时候都会生成一个执行环境,这个执行环境怎么表达呢?js为每个执行环境关联一个变量对象。环境中定义的所有变量和函数都存储在该对象中。无块作用域:if(true){varda="dada";}console.log(da);functionadd(num1,num2){varnum=num1+num2;returnnum;}undefinedvarresult=add(1,2);undefinedconsole.log(result);VM962:13undefined向上查询:varda="dada";functiongetDa(){varda="dadada";returnda;}console.log(getDa());JavaScript中最常见的垃圾收集方法是标记清除,另一种不太常见的垃圾策略称为引用计数。基本类型值和引用类型值:基本类型值在内存中占用固定空间,存放在栈内存中。将一个基本类型的值从一个变量复制到另一个变量,会创建这个值的副本,而引用类型的值作为对象,存放在堆内存中。包含引用类型值的变量实际上并不包含对象本身,而是指向对象的指针。typeof运算符确定一个值是哪种基本类型,instanceof运算符确定一个值是哪种引用类型。执行环境分为:全局执行环境和函数执行环境。每次进入新的执行环境时,都会创建一个用于搜索变量和函数的作用域链。??别忘了留下学习的足迹【点赞+收藏+评论】AuthorInfo:【作者】:Jeskson【原创公众号】:达达前端小酒馆。【福利】:公众号回复“信息”,送自学资料大礼包(进群分享,想要什么就说,看我有没有)!【转载说明】:转载请注明出处,谢谢合作!~大前端开发,定位前端开发技术栈博客,PHP背景知识点,web全栈技术领域,数据结构与算法,网络原理等以通俗易懂的方式呈现给小伙伴方式。感谢您的支持,感谢您的厚爱!!!如本账号内容有问题(例如:涉及版权或其他问题),请及时联系我们进行整改,我们会尽快处理。请喜欢它!因为您的认可/鼓励是我写作最大的动力!欢迎来到达达的CSDN!这是一个有品质有态度的博客