美文网首页
作用域/闭包

作用域/闭包

作者: LoveBugs_King | 来源:发表于2019-04-04 21:23 被阅读0次

又来复习概念了,这次因为理解“执行环境”、“作用域”、“this指向的对象” 、“闭包函数”概念出现了混乱。网上每个点都有很多不同说法,看的很晕,所以自己翻了一下《js高程》,再次理解了一遍,记录一下,方便以后忘记再次理解。

执行环境
    概念:每个执行环境都有一个与之关联的变量对象,环境中定义的变量和函数都保存在这个对象中。我们无法访问它,后台解析器处理数据时会用到它。
    运行原理:除了全局环境,每个函数都有自己的执行环境。当前函数运行时,会把当前函数的环境推入“环境栈”中,函数执行完毕后,“环境栈”将其推出,把控制权返回给之前的环境,接而推入下一个函数执行环境。
    销毁时机:某个执行环境中的所有代码执行完毕,环境被销毁,保存在其中的所有变量和函数也都被销毁(全局环境直到应用程序关闭时才会销毁,比如关闭网页)。

作用域
    概念:当代码在一个环境中执行时,会创建变量对象的一个作用域链,用来保证对执行环境内的变量和函数进行有序的访问。
    作用域链:先是当前执行环境的变量对象,下一个变量是外部环境,下下一个变量是外外部环境,直到全局环境为止。
    活动对象:如果当前环境是函数,则变量对象是其活动对象(最开始只包含arguments对象,另外这个对象在全局环境中是不存在arguments的)。
    访问规则:内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量。

一个函数被调用时,会创建一个执行环境 以及 一个相应的作用域链。然后,使用arguments和其它命名参数的值来初始化函数的活动对象。

例子

    在创建compare()函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。
    当调用compare()函数时,会为函数创建一个执行环境,复制[[Scope]]属性中的对象成为当前环境的作用域链的变量对象,之后往这个作用域链中推入当前函数的活动对象(arguments、v1、v2)作为变量对象。
    所以compare函数的作用域链中包含两个变量对象:本地活动对象和全局变量对象。
    当compare函数执行完毕,本地活动对象就随环境一起被销毁,内存被释放,内存中仅保存全局作用域。

但是闭包的情况又有所不同。

闭包概念:有权访问另一个函数作用域中的变量的函数(函数a内嵌套函数b,b函数就算闭包)。

闭包函数例子

a函数初始化时,其作用域链中有全局变量对象。
a函数调用时( var b = a('age') ),其作用域中增加了本地活动对象(arguments、o1)。
a函数执行完毕,返回匿名函数。a函数的环境和作用域链被销毁,但其活动对象不被销毁(因为还在被匿名函数引用)。
匿名函数初始化,其作用域链中有全局变量对象、a函数活动对象。
匿名函数调用( b({age:10},{age:11}) ),其作用域链中有全局变量对象、a函数活动对象,本地活动对象(arguments、q1、q2)。
匿名函数结束调用,a函数的活动对象和匿名函数的变量对象全部被销毁。

注意:因为全局变量b中保存着对匿名函数的引用,其实匿名函数的变量对象和a的活动对象并不会被销毁,导致内存泄漏
解决:var b = null。

再来看一个例子

函数a返回了一个函数数组res。结果是res的10个函数都是 "return 10"。这是为什么
    这10个函数都是匿名函数,他们在初始化时,作用域链中包含 “函数a的活动对象、全局变量对象”。那么其“return i”的i来自函数a的活动对象。当res被返回时,i已经变成10,各个函数的作用域链中的a的活动对象中的i也都是10。
    这是因为,如果外部函数有1个变量的值反复被更新,对于该变量,闭包函数只能取得最后一个值。

那我们让它正常的返回1-10,该怎么做

解决方法

    我们不要让i来自a函数的活动对象,因为它最后的值是10。我们再在中间加一层函数b(i){...}并接受i的值作为活动对象,此时闭包函数初始化时的作用域链包含“函数b的活动对象,函数a的活动对象、全局变量对象”。而函数b的活动对象i,没有进行变化,闭包就能取得i的值为1-10。

关于this对象记住两点
    1、this对象是函数在运行时基于函数的执行环境绑定的。
    2、我们直到函数在被调用时,都会自动取得两个特殊变量thisarguments函数内在搜索这两个变量时只会搜索到自己的活动对象,不会像其它普通变量一样通过作用域向上去搜索。

例子1

b()其实就是window.b(),执行环境是window对象,所以this对象绑定的是window对象,也就返回了全局对象‘111’。

例子2

首先obj.getA()函数的执行环境是obj,所以getA函数的this对象也就指向obj。
obj.getA()返回的匿名函数,该函数的执行环境是全局环境,所以this指向全局对象,也就返回"111"。
你可能会误以为匿名函数的this对象会根据作用域往上查找,其实并不会。

例子3

h函数是自己执行的,相当于执行环境是全局环境。

例子4

obj.getA()的执行环境是obj,函数内的this也就指向obj。
把obj.get函数取出来后,在外部执行,执行环境就是全局环境,函数内的this也就指向全局变量。

例子5

o.b.fn(),函数fn的执行环境是b对象,但b对象中并无a变量,所以返回undefined。

当this碰到return时:如果返回值是一个对象(不包括null),那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例

当碰到return时

相关文章

  • 作用域和闭包

    目录 概述 作用域编译过程词法作用域全局作用域函数作用域 闭包循环和闭包闭包的用途性能 总结 概述 作用域和闭包一...

  • 2018-01-07 关于javascript闭包和作用域的理解

    关于 javascript 闭包的一些思考 作用域 词法作用域 函数作用域 块作用域 闭包 什么是作用域? 作用域...

  • js作用域、闭包

    闭包 闭包作用 全局 局部 作用域链

  • javaScript门道之闭包

    闭包的学习路径:变量的作用域 -> 闭包的概念 ->闭包的应用 1.变量的作用域 变量的作用域分为作用于全局和作用...

  • 14.JS基础之作用域与闭包

    作用域: 全局作用域 函数作用域 块级作用域(ES6新增) 常见的闭包有:作为函数返回值的闭包与作为函数参数的闭包...

  • 执行环境 & 作用域 & 闭包

    执行环境 & 作用域 & 闭包 执行环境 , 作用域 , 闭包 , 闭包应用 执行环境 执行环境定义了 当前环境的...

  • js 总结七07-19

    作用域 全局 局部 作用域链 闭包

  • 2023-01-12

    变量提升调用栈块级作用域作用域链和闭包 闭包 => 作用域链(词法作用域) => 调用栈(栈溢出) => 上下文...

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

  • js闭包

    由于作用域的关系,函数之间不能相互读取变量,父级作用域不能读取子级作用域的变量。这是闭包出现了。 闭包 闭包就是能...

网友评论

      本文标题:作用域/闭包

      本文链接:https://www.haomeiwen.com/subject/xtvfiqtx.html