作用域链和闭包的关系(作用域链和闭包的区别)

      最后更新:2023-03-28 15:20:25 手机定位技术交流文章

      js闭包是什么?

      js闭包是一个拥有许多变量和绑定了这些变量的环境的表达式。闭包的特点:1、作为一个函数变量的一个引用,当函数返回时,其处于激活状态,一个闭包就是当一个函数返回时,一个没有释放资源的栈区。2、js闭包允许使用内部函数,这些内部函数可以访问它们所在的外部函数中声明的参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。扩展资料:js闭包实例:1、函数内部可以直接读取全局变量function parent(){m=50;}parent();alert(m);//50参考资料来源:百度百科:javascript闭包
      闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 闭包有三个特性:1.函数嵌套函数2.函数内部可以引用外部的参数和变量3.参数和变量不会被垃圾回收机制回收闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量使用闭包有一个优点,也是它的缺点,就是可以把局部变量驻留在内存中,可以避免使用全局变量。全局变量在每个模块都可调用,这势必将是灾难性的。所以推荐使用私有的,封装的局部变量。一般函数执行完毕后,局部活动对象就被销毁,,内存中仅仅保存全局作用域。但闭包的情况不同!嵌套函数的闭包:function aaa() {var a = 1;return function(){alert(a++)};}var fun = aaa();fun();// 1 执行后 a++,,然后a还在~fun();// 2fun = null;//a被回收!!以上输出结果为5; 闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。
      js中的局部变量出了作用于就会被垃圾回收机制回收,这时候如果想长久保存这个变量不被回收就要用到闭包。 真心想学习JS、以后想朝着这个方向发展,那么你一定要来这个企鹅裙,前面前面是二九六,中间是五九1,最后面就是二九0,连起来就是完整的噢,来这里可以这里学习经验,得到专人解答,这样你可以成长的更快,期待你的加入!!!闭包的规则是:1,函数嵌套函数。2,内部函数使用了外部函数的变量或者参数。下面有个二级菜单的小案例就是使用了闭包的特性:
    1. 0
    2. 1
    3. 2
    4. 这就是闭包的一个应用。
      我初次接触“闭包”时,看了很多资料,总是无法理解,因为一些文章写得太“学术化”,虽然措辞非常严谨,但是对初学这来说,太难理解了。 自从看到这篇文章,我的眼前“豁然开朗”一、什么是闭包?“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。相信很少有人能直接看懂这句话,因为他描述的太学术。我想用如何在Javascript中创建一个闭包来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。看下面这段代码:function a(){var i=0;function b(){alert(++i);}return b;}var c = a();c();这段代码有两个特点:1、函数b嵌套在函数a内部;2、函数a返回函数b。引用关系如图:这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。我猜想你一定还是不理解闭包,因为你不知道闭包有什么作用,下面让我们继续探索。二、闭包有什么作用?简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。那 么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。(关于Javascript的垃圾回收机制将在后面详细介绍)三、闭包内的微观世界如 果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。1、当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。2、当函数a执行的时候,a会进入相应的执行环境(excution context)。3、在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。4、然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。5、下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。6、最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。当函数b执行的时候亦会像以上步骤一样。因此,执行时b的作用域链包含了3个对象:b的活动对象、a的活动对象和window对象,如下图所示:如图所示,当在函数b中访问一个变量的时候,搜索顺序是先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依 次查找,直到找到为止。如果整个作用域链上都无法找到,则返回undefined。如果函数b存在prototype原型对象,则在查找完自身的活动对象 后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。四、闭包的应用场景1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。以上两点是闭包最基本的应用场景,很多经典案例都源于此。五、Javascript的垃圾回收机制 在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
      当函数被保存到了外部,将会生成闭包,闭包会导致原有作用域链不释放,造成内存泄漏
      js闭包是什么?

      Web前端知识体系简介

      今天小编要跟大家分享的文章是关于Web前端知识体系简介。Web前端技术由html、css和javascript三大部分构成,是一个庞大而复杂的技术体系,其复杂程度不低于任何一门后端语言。而我们在学习它的时候往往是先从某一个点切入,然后不断地接触和学习新的知识点,因此对于初学者很难理清楚整个体系的脉络结构。本文将对Web前端知识体系进行简单的梳理,对应的每个知识点点到为止,不作详细介绍。目的是帮助大家审查自己的知识结构是否完善,如有遗漏或不正确的地方,希望共勉。下面来和小编一起看一看吧! 一、JAVASCRIPT篇0、基础语法Javascript基础语法包括:变量定义、数据类型、循环、选择、内置对象等。数据类型有string,number,boolean,null,undefined,object等。其中,string,number和boolean是基础类型,null和undefined是JS中的两个特殊类型,object是引用类型。Javascript可以通过typeof来判断基础数据类型,但不能够准确判断引用类型,因此需要用到另外一个方法,那就是Object的toString,关于数据类型及其判断可以参考以下博客:数据类型详解和判断JS数据类型的四种方法JS常用的内置对象有Date、Array、RegExp等。一般来讲,Date和Array用的最频繁,正则表达式RegExp是处理字符串的利器。关于数据和正则表达式的用法可以参考博客:ES5对数组增强的9个API和JS正则表达式精简1、函数原型链Javascript虽然没有继承概念,但Javascript在函数Function对象中建立了原型对象prototype,并以Function对象为主线,从上至下,在内部构建了一条原型链。简单来说就是建立了变量查找机制,当访问一个对象的属性时,先查找对象本身是否存在,如果不存在就去该对象所在的原型连上去找,直到Object对象为止,如果都没有找到该属性才会返回undefined。因此我们经常会利用函数的原型机制来实现JS继承。关于函数原型链可参考博客:JS原型对象和原型链2、函数作用域函数作用域就是变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。在JS中没有会块级作用域,只有函数作用域,因此JS中还存在着另外一种怪异现象,那就是变量提升。关于作用域的介绍请参考博客:函数的作用域和作用域链3、函数指针thisthis存在于函数中,它指向的是该函数在运行时被调用的那个对象。在实际项目中,遇到this的坑比较多,因此需要对this作深入的理解。Function对象还提供了call、apply和bind等方法来改变函数的this指向,其中call和apply主动执行函数,bind一般在事件回调中使用,而call和apply的区别只是参数的传递方式不同。关于call,apply和bind的用户请参考博客:详解JS的call,apply和bind4、构造函数newJS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。普通函数的创建有:显式声明、匿名定义、newFunction()等三种方式。当通过new来创建一个新对象时,JS底层将新对象的原型链指向了构造函数的原型对象,于是就在新对象和函数对象之间建立了一条原型链,通过新对象可以访问到函数对象原型prototype中的方法和属性。new的详细介绍请参考博客:理解JS中的new运算符5、闭包闭包其实是一个主动执行的代码块,这个代码块的特殊之处是可以永久保存局部变量,但又不污染全局变量,可以形成一个独立的执行过程,因此我们经常用闭包来定义组件。关于闭包的介绍请参考:干货分享:让你分分钟学会JS闭包6、单线程和异步队列setTimeout和setInterval是JS内置的两个定时器,使用很简单,但这两个方法背后的原理却不简单。我们知道,JS是单线程语言,在浏览器中,当JS代码被加载时,浏览器会为其分配一个主线程来执行任务(函数),主线程会形成一个全局执行环境,执行环境采用栈的方式将待执行任务按顺序依次来执行。但在浏览器中有一些任务是非常耗时的,比如http请求、定时器、事件回调等,为了保证其他任务的执行效率不被影响,JS在执行环境中维护了一个异步队列(也叫工作线程),并将这些任务放入队列中进行等待,这些任务的执行时机并不确定,只有当主线程的任务执行完成以后,才会去检查异步队列中的任务是否需要开始执行。这就是为什么setTimeout(fn,0)始终要等到最后执行的原因。关于单线程和异步队列问题请参考:setTimeout(0)7、异步通讯Ajax技术Ajax是浏览器专门用来和服务器进行交互的异步通讯技术,其核心对象是XMLHttpRequest,通过该对象可以创建一个Ajax请求。为了防止XSS攻击,浏览器对Ajax做了限制,不允许Ajax跨域请求服务器,就是只能访问当前域名下的url。当然,如果确信你的站点不存在跨域的风险,可以在服务端主动开启跨域请求,也可以通过CORS或JSONP来实现。JSONP是利用脚本(script)跨域能力来模拟Ajax请求。CORS是一个W3C标准,全称是"跨域资源共享"(Cross-originresourcesharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。关于CORS的介绍请参考:跨域资源共享CORS详解8、DOM对象documentdocument对象里保存着整个Web页面dom结构,在页面上所有的元素最终都会映射为一个dom对象。document也提供了很多api来查找特定的dom对象,比如getElementById,querySelector等等。9、事件系统Event事件是用户与页面交互的基础,到目前为止,DOM事件从PC端的鼠标事件(mouse)发展到移动端的触摸事件(touch)和手势事件(guesture)由于DOM结构可能会多层嵌套,因此也衍生出了两种事件流:事件捕获和事件冒泡,后者最常用。利用事件冒泡机制可以实现很多功能,比如页面点击统计。关于两种事件流的介绍请参考:事件冒泡和捕获除此之外,在页面初始化、滚动、隐藏、返回等操作时分别内置了onload/onDOMContentLoaded、onscroll、onvisibility和onhashchange等事件,如果想要捕获这些事件,需要通过addEventLisener/attachEvent来进行绑定。10、全局对象window在JS中,当一段JS代码在浏览器中被加载执行,JS引擎会在内容中构建一个全局执行环境,执行环境的作用是保证所有的函数能按照正确的顺序被执行,而window对象则是这个执行环境中的一个全局对象,window对象中内置了很多操作api和对象,document对象就是其中一个。关于JS执行环境的介绍请参考博客:深入理解JS执行细节二、CSS篇css是用来对html进行修饰的一门语言。1、选择器css的选择器有很多种,常用的有类选择器、标签选择器、ID选择器、后代选择器、群组选择器、伪类选择器(before/after)、兄弟选择器(+~)、属性选择器等等。2、定位定位一般有相对定位(relative)、绝对定位(absolute)、固定定位(fixed),relative和absolute在移动端用的最多,fixed在移动端的兼容性有问题,因此不推荐使用,在移动端替代fixed的方案是absolute+内部滚动。3、浮动设置float为left或right,就能使该元素脱离文档流,向左或向右浮动。一般在做宫格模式布局时会用到,如果子元素全部设置为浮动,则父元素是塌陷的,这时就需要清除浮动,清除浮动的方法也很多,常用的方法是在元素末尾加空元素设置clear:both,更高级一点的就给父容器设置before/after来模拟一个空元素,还可以直接设置overflow:auto/hidden。除过浮动可以实现宫格模式,行内盒子(inline-block)和table也可以。4、盒子模型盒子模型是css最重要的一个概念,也是css布局的基石。常见的盒子模型有块级盒子(block)和行内盒子(inline-block),盒子最关键的几个属性包括margin、border、padding和content,这几个元素可以设置盒子和盒子之间的关系以及盒子和内容之间的关系。还有一个问题是计算盒子的大小,需要注意的是,box-sizing属性的设置会影响盒子的width和height。只有普通文档流中块框的垂直外边距才会发生外边距合并。行内框、浮动框或绝对定位之间的外边距不会合并。5、Flex布局Flex布局的容器是一个伸缩容器,首先容器本身会更具容器中的元素动态设置自身大小;然后当Flex容器被应用一个大小时(width和height),将会自动调整容器中的元素适应新大小。Flex容器也可以设置伸缩比例和固定宽度,还可以设置容器中元素的排列方向(横向和纵向)和是否支持元素的自动换行。有了这个神器,做页面布局的可以方便很多了。注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。6、transition(过渡)和transform(旋转)应用transform可以对元素进行平移(translate)、旋转(rotate)、放大缩小(scale)、倾斜(skew)等处理,而transition使css属性值(包括transform)在一段时间内平滑的过渡。使用transition和transform就可以实现页面的滑动切换效果。7、动画AnimationAnimation首先需要设置一个动画函数,然后以这个动画的方式来改变元素的css属性之的变化,动画可以被设置为永久循环演示。和transition相比,animation设置动画效果更灵活更丰富,二者还有一个区别是:transition只能通过主动改变元素的css值才能触发动画效果,而animation一旦被应用,就开始执行动画。8、Sprite图对于大型站点,为了减少http请求的次数,一般会将常用的小图标排到一个大图中,页面加载时只需请求一次网络,然后在css中通过设置background-position来控制显示所需要的小图标。9、字体图标iconfont所谓字体图标就是将常用的图标转化为字体资源存在文件中,通过在CSS中引用该字体文件,然后可以直接通过控制字体的css属性来设置图标的样式。三、HTML篇1、Web语义化和SEOhtml常规标签有html,head,body,div,span,table,ul,ol,dl,p,b,h1~h6,strong,form,input,img,em,i等等,另外html5还新增了很多语义化的标签,比如header,acticle,aside,section,footer,audio,radio等等。Web语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解。SEO是指在了解搜索引擎自然排名机制的基础之上,对网站进行内部及外部的调整优化,改进网站在搜索引擎中关键词的自然排名,获得更多的展现量,吸引更多目标客户点击访问网站,从而达到互联网营销及品牌建设的目标。搜索引擎通过爬虫技术获取的页面就是由一堆html标签组成的代码,,人可以通过可视化的方式来判断页面上哪些内容是重点,而机器做不到。但搜索引擎会根据标签的含义来判断内容的权重,因此,在合适的位置使用恰当的标签,使整个页面的语义明确,结构清晰,搜索引擎才能正确识别页面中的重要内容,并予以较高的权值。比如h1~h6这几个标签在SEO中的权值非常高,用它们作页面的标题就是一个简单的SEO优化。2、本地存储本地存储最原始的方式就是cookie,cookie是存放在本地浏览器的一段文本,数据以键值对的形式保存,可以设置过期时间。但是cookie不适合大量数据的存储,因为每次请求一次页面,cookie都会发送给服务器,这使得cookie速度很慢而且效率也不高。因此cookie的大小被限制为4k左右(不同浏览器可能不同,分HOST),如下所示:·Firefox和Safari允许cookie多达4097个字节,包括名(name)、值(value)和等号。·Opera允许cookie多达4096个字节,包括:名(name)、值(value)和等号。·InternetExplorer允许cookie多达4095个字节,包括:名(name)、值(value)和等号。在所有浏览器中,任何cookie大小超过限制都被忽略,且永远不会被设置。html5提供了两种在客户端存储数据的新方法:localStorage和sessionStorage,它们都是以key/value的形式来存储数据,前者是永久存储,后者的存储期限仅限于浏览器会话(session),即当浏览器窗口关闭后,sessionStorage中的数据被清除。localStorage的存储空间大约5M左右(不同浏览器可能不同,分HOST),这个相当于一个5M大小的前端页面的数据库,相比于cookie可以节约带宽,但localStorage在浏览器隐私模式下是不可读取的,当存储数据超过了localStorage的存储空间后会抛出异常。此外,H5还提供了逆天的Websql和indexedDB,允许前端以关系型数据库的方式来存储本地数据,相对来说,这个功能目前应用的场景比较少,此处不作介绍。3、浏览器缓存机制浏览器缓存机制是指通过HTTP协议头里的Cache-Control(或Expires)和Last-Modified(或Etag)等字段来控制文件缓存的机制。Cache-Control用于控制文件在本地缓存有效时长。最常见的,比如服务器回包:Cache-Control:max-age=600表示文件在本地应该缓存,且有效时长是600秒(从发出请求算起)。在接下来600秒内,如果有请求这个资源,浏览器不会发出HTTP请求,而是直接使用本地缓存的文件。Last-Modified是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过If-Modified-Since字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。Cache-Control通常与Last-Modified一起使用。一个用于控制缓存有效时间,一个在缓存失效后,向服务查询是否有更新。Cache-Control还有一个同功能的字段:Expires。Expires的值一个绝对的时间点,如:Expires:Thu,10Nov201508:45:11GMT,表示在这个时间点之前,缓存都是有效的。Expires是HTTP1.0标准中的字段,Cache-Control是HTTP1.1标准中新加的字段,功能一样,都是控制缓存的有效时间。当这两个字段同时出现时,Cache-Control是高优化级的。Etag也是和Last-Modified一样,对文件进行标识的字段。不同的是,Etag的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match字段把特征字串发送给服务器,由服务器和文件最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。Etag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。另外有两种特殊的情况:·手动刷新页面(F5),浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。·强制刷新页面(Ctrl+F5),浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或Pragma:no-cache),发包向服务重新拉取文件。4、HTML5离线缓存HTML5离线缓存又叫ApplicationCache,是从浏览器的缓存中分出来的一块缓存区,如果要在这个缓存中保存数据,可以使用一个描述文件(manifestfile),列出要下载和缓存的资源。manifest文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。manifest文件可分为三个部分:-CACHEMANIFEST-在此标题下列出的文件将在首次下载后进行缓存-NETWORK-在此标题下列出的文件需要与服务器的连接,且不会被缓存-FALLBACK-在此标题下列出的文件规定当页面无法访问时的回退页面(比如404页面)离线缓存为应用带来三个优势:·离线浏览-用户可在应用离线时使用它们·速度-已缓存资源加载得更快·减少服务器负载-浏览器将只从服务器下载更新过或更改过的资源。5、Canvas和SVGCanvas通过Javascript来绘制2D图形。Canvas是逐像素进行渲染的。在Canvas中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。SVG是一种使用XML描述2D图形的语言。SVG基于XML,这意味着SVGDOM中的每个元素都是可用的。你可以为某个元素附加JavaScript事件处理器。在SVG中,每个被绘制的图形均被视为对象。如果SVG对象的属性发生变化,那么浏览器能够自动重现图形。Canvas和SVG相比,canvas更依赖于分辨率,不支持事件处理器,文本渲染能力弱,比较适合密集型游戏,其中的许多对象会被频繁绘制,而svg则比较适用于类似谷歌地图带有大型渲染区域的应用程序。以上就是小编今天为大家分享的Web前端知识体系简介的文章,希望本篇文章能够对正在从事Web工作和学习Web前端知识的小伙伴们有所帮助。想要了解更多Web前端知识记得关注北大青鸟Web培训官网。最后祝愿小伙伴们工作顺利!原文地址:#/onepixel/p/7021506.html
      Web前端知识体系简介

      面向对象中的对象上下文(对象环境)和对象作用域到底指什么意思啊?这种专业术语让我很是头痛。。

      作用域: 首先,在javascript中的每个函数都是对象,是Funtion对象的一个实例,而Funtion中有一系列仅供javascript引擎存取的内部属性,其中一个便是[[scope]],它包含了一个函数被创建的作用域中对象的集合,这个集合就是函数的作用域链。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:function add(num1,num2){var sum = num1+num2;return sum;}在函数add创建时,它的作用域链中会填入一个单独的可变对象,即全局对象,该全局对象包含了所有全局变量,函数add的作用域将在执行时候用到,假设vartotal = add(5,10);执行此函数会创建一个称为执行上下文的内部对象,一个执行上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用统一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁。每个执行下文都有自己的作用域链,用于标识符解析,当执行上下文被创建时,它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activationobject)”,活动对象作为函数运行期的可变对象,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,即它通过函数的arguments属性初始化,arguments属性的值是Arguments对象:【Arguments对象是活动对象的一个属性,它包括如下属性:callee — 指向当前函数的引用length — 真正传递的参数个数properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。properties-indexes内部元素的个数等于arguments.length. properties-indexes的值和实际传递进来的参数之间是共享的。这个共享其实不是真正的共享一个内存地址,而是2个不同的内存地址,使用JavaScript引擎来保证2个值是随时一样的,当然这也有一个前提,那就是这个索引值要小于你传入的参数个数,也就是说如果你只传入2个参数,而还继续使用arguments[2]赋值的话,就会不一致,如:function b(x, y, a) {arguments[2] = 10;alert(a);}b(1, 2);这时候因为没传递第三个参数a,所以赋值10以后,alert(a)的结果依然是undefined,而不是10,但如下代码弹出的结果依然是10,因为和a没有关系。function b(x, y, a) {arguments[2] = 10;alert(arguments[2]);}b(1, 2);】然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。注意:如果名字相同的两个变量存储在作用域链的不同部分,那么标识符就是遍历作用域时最先找到的那一个。闭包:闭包,简单点说就是函数里面嵌套函数如:function a(){var name,age;function b(){console.log(name);console.log(age);}}例子中的b函数就是一层闭包,闭包的强大之处在于它允许函数访问作用域之外的数据,如例子中在b函数内部访问a函数中的变量,在看一个例子:funtion assignEvents(){var id = "xdi9592";document.getElementById("save-btn").onclick = function(event){saveDocument(id);}}assignEvents函数中的事件处理器就是一个闭包,他在assignEvents执行时被创建,并且能访问所属作用域的id变量。当assignEvents()被执行时,一个包含了变量id和其他一些数据的活动对象被创建,即为运行期上下文作用域中的一个对象,当闭包被创建时,它的[[scope]]属性被初始化为这些对象,因为闭包的[[scope]]属性包含了与运行期上下文作用域链相同的对象的引用,因此,当外层函数执行完毕时,由于引用仍然存在闭包的[[scope]]属性中,故活动对象无法被销毁,会使内存消耗大,即造成内存泄漏。 当闭包被执行的时候,一个执行上下文又被创建,它的作用域链与属性[[scope]]中引用的两个相同的作用域链对象同时被初始化,然后一个活动对象被闭包自身所创建
      面向对象中的对象上下文(对象环境)和对象作用域到底指什么意思啊?这种专业术语让我很是头痛。。

      关于闭包的理解问题,小白求大牛解答!!

      首先应该深入的理解一下闭包的概念,维基百科上关于闭包的解释理解起来比较容易些,我把前面两段话简单的处理一下:在程序语言中,闭包(Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。闭包是由函数和与其相关的引用环境组合而成的实体。在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。理解了闭包之后,再来看你的第一个问题,虽然A处的inc函数只是声明,但是闭包在外层函数a执行的时候就已经生成,形成的闭包包括了内部函数的代码和所需外部变量的引用。根据定义,还有一点需要注意,即形成的闭包保存的是外部变量的引用,看下面的例子: var arr = []; for (var i=0; i<3; i++) { arr[i] = return function() {         alert(i)     } } arr[0](); arr[1](); arr[2]();每次都是弹出3,即闭包只记住外部变量存放在了哪里,在内部函数还没有执行前,它是不管你的值是什么的,任你怎么变,我执行的时候只获取最后的值。要想实现想要的效果,可以这样做: var arr = []; for (var i=0; i<3; i++) { arr[i] = function(j) { return function() { alert(j) } }(i) } arr[0](); arr[1](); arr[2]();这里用一个立即执行函数,使得每次循环的i值都记录下来了。你的第二个问题看了好几遍还是不太理解你想问什么,简单的说一些常识吧。function a(...)和var a=function(...)是函数的两种声明方式,无论哪一种,只要你没有重新给a赋值,即a还指向这个函数,那么这个函数所占据的内存就不会被回收,函数执行完毕后回收的只是函数内部声明的局部变量(如果变量没有被内部函数引用形成闭包),故而函数的局部变量在函数每次执行时都重新定义,重新赋值。
      return inc;这一句是将整个函数给return出去,var c = a();这里将函数a的返回值接收,实际上c就是函数inc了,你打印一下c,看看c是什么,var c = a();console.log(c);调用c,其实就是在调用inc这个函数。你就这么理解吧,只要知道c = inc()就行了。这样说你能明白吗?
      关于闭包的理解问题,小白求大牛解答!!

      简单的闭包问题?

      概念闭包,在《javascripts高级程序设计》里面是这样介绍的:闭包是指有权访问另一个作用域中的变量的函数。额。。这句话我以前看过很多遍,但依然不是很懂,只知道它是跟作用域有关。现在我知道了,如果这句话换成:但凡是内部的函数被保存到了外部,必定生成闭包。这样就容易理解多了不是。我们以下面的这个代码块为例:例子解释function a() {const num = 100;function b () {num++;console.log(num);}return b;}const demo = a();demo();demo();我们先执行上述代码,看看结果是什么:为什么是这样呢?a()执行的结果是返回b,所以demo指的是b,则demo()指的是b();也就是说原先在a里面的b,在b的外部执行;我们已经知道了作用域和作用域链的概念,上面代码的作用域是这样的:a执行完,返回了b,此时的b只是声明,但还没调用,所以没有形成自己的AO,但作用域链和 a doing 时是一样的,所以虽然 a() 的作用域被销毁了,但是相同的一份却被b保存到了外面。这也就是内部函数被保存到了外面形成闭包的本质。这样也不难理解为什么上述代码打印出来的值是那样的了:执行第一个demo()时,也即是执行 b(),由于b保存了a的作用域链,所以也可以访问到 num ,执行 b() 后,加一;那为什么第二次执行 demo(),打印出的值还是有自增了呢?这是因为操作的都是保存在 b 里的 num ,虽然每次调用 demo() 都会形成新的作用域链,但是num,却是每次从上一次的作用域链直接 copy到当前作用域链中的。这样形成的闭包虽然可以使外部可以访问到内部的函数,但是导致了原有的作用域链不释放,会造成内存泄漏。(内存泄漏的意思就是占用内存,可用内存资源变少了)。所以如果不是特殊需要,应尽量防止这种情况发生。并且,作用域链的配置机制引出了一个值得注意的副作用:即闭包只取得包含函数中任何变量最后一个值,比如下面这个例子:function createFunctions() {var result = [];for(let i = 0; i< 10; i++) {result[i] = function() {console.log(i);}}return result;}var myArr = createFunctions();for(var j = 0; j < 10; j++) {myArr[j]();}这个函数会返回一个函数数组,表面上看,似乎每个函数都应该有自己的索引值,即会返回:0,1,2...9;但实际上,每个函数都会返回10;这是因为在createFunctions()执行时,for循环跳出的条件是i=10;所以函数返回后,i的值是10 ;而每个result的作用域链中都保存这createFunctions()的AO,所以他们引用的都是createFunctions()的i值,所以每个函数内部i的值都是10;这样,我们可以创建一个立即执行函数强制让闭包的行为符合预期:function createFunctions() {var result = [];for(var i = 0; i < 10; i++) {(function(j) {result[i] = function() {document.write(j + " ");}}(i));}return result;}var myArr = createFunctions();for(var j = 0; j < 10; j++) {myArr[j]();}典型应用下面看看几个用到闭包的典型例子:实现共有变量如累加器:调用多少次,累加多少次,用闭包更加模块化function add() {var count = 0;function demo() {count++;console.log(count);}return demo;}var counter = add();counter();//1counter();//2counter();//3实现缓存如eater: eat和push保存的都是eater的AO;,所以eat中food改变后。实际上是eater变了,所以也会影响push;function eater() {var food = '';var obj = {eat: function() {console.log('eating' + food);food = '';},push: function(myFood) {food = myFood;}}return obj;// 相当于返回里面的eat和push操作food;}var eater1 = eater();eater1.push('banana');eater1.eat();
      闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数看作对象,然后能像在对象中的操作般在函数中定义实例(局部)变量,而这些变量能在函数中保存到函数的实例对象销毁为止
      简单的闭包问题?

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/61151.html

          热门文章

          文章分类