资讯专栏INFORMATION COLUMN

JS核心知识点梳理——上下文、作用域、闭包、this(上)

Andrman / 1609人阅读

摘要:引言满满的干货,面试必系列,参考大量资料,并集合自己的理解以及相关的面试题,对核心知识点中的作用域闭包上下文进行了梳理。如果在小区这个作用域找到了张老师,我就会在张老师的辅导下学钢琴我张老师房间钢琴构成了学琴的上下文环境。

引言

满满的干货,面试必bei系列,参考大量资料,并集合自己的理解以及相关的面试题,对JS核心知识点中的作用域、闭包、this、上下文进行了梳理。由于篇幅有限,这里只对我认为最重要的知识做了介绍,一些常识性的东西大家可以参考高程。

上下文(execution context)

又叫执行环境,环境。

执行环境定义了变量或者环境有权访问的其他数据,据定了它们的各自行为 --高程

一个函数执行的时候,会产生一个属于自己的执行环境。环境里面有一个变量对象variable object(VO),OA里面存放着环境中定义的所有变量和函数,作用域链(scope chain),this。
函数执行,环境产生被推入环境栈,函数执行完,环境出栈并被销毁(闭包例外),把控制权返回给之前的执行环境。

作用域
js中的作用域是静态作用域,静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区域内可见(visibility);在这段区域以外该变量不可见(或无法访问)。词法作用域里,取变量的值时,会检查函数定义时的文本环境,捕捉函数定义时对该变量的绑定。--wiki
作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。--你不知道的javascript

作用域就是执行的时候,给环境变量赋值的一种规则,这种规则在函数定义的时候就已经确定了,和运行无关
js只有全局作用域和函数作用域,没有块作用域。

变量提升

我们把定一个变量的行为分为两个过程,声明和定义

var a = 1
//实际执行的是下面两步
var a 
a = 1

var的变量声明会提升,没有var就是全局变量,let没,const有变量提升
var的函数声明和赋值都提升

a //undefined 因为a的声明已经提升到最上面了
var a = 1

f() //alert 1
function f () {
    alert (1)
}

有几个特殊的地方虽然平时不会这么写,但是面试题会遇到:

函数体中,return后面的代码不进行变量提升,但是return下面的代码要进行变量提升

不管条件是否成立,都要进行变量提升;

匿名函数不进行 变量提升;

如果变量名字发生重复,那么不再重复声明,但是要重新定义;

执行环境和作用域的关系

很多人都分不清楚执行环境和作用域的关系。其实很简单,作用域和上下文完全是两个不相干的东西。
作用域是一种规格,声明函数的时候就已经确定了。
执行环境是函数执行的时候产生的,函数在执行环境中执行。大家看下面例子

alert(a) //a is not defined

执行的时候VO里面没有a,因为根据VO作用域链【windows】,按照规则找不到a。

var a  = 1
alert(a)  // alert 1

执行的时候,根据规则,从VO作用域链【windows】头部window作用域开始找a,找到a了,a为1,则vo中a设置为1,所以alert 1

var a  = 1
function foo() {
    var a = 100 
    alert(a) 
}
foo() //  alert 100

执行的时候,根据规则,从VO作用域链【windows-foo】头部foo作用域开始找a,找到a了,a为100,则vo中a设置为100,所以alert 100

var a  = 1
function foo() {
    alert(a) 
}
foo() //  alert 1

执行的时候,根据规则,从VO作用域链【windows-foo】头部foo作用域开始找,没找到a。根据规则,沿上层作用域(也就是window)开始找,找到a了,a为1。则vo中a设置为1,所以alert 1

再说一个通俗一点的的比喻。
我需要找个优秀的音乐老师辅导我弹琴,我在老师的指导下弹琴好比是是函数执行
小区这个作用域找不到好老师,我本市找。
本市这个作用域找不到好老师,我本省找。
省这个作用域还找不到好老师,我全国找。
国家这个作用域还找不到。我就没办法了,钢琴学不会了(函数报错)。
如果在小区这个作用域找到了张老师,我就会在张老师的辅导下学钢琴,我、张老师、房间、钢琴构成了学琴的上下文环境
我学完了,但是我把学琴的这件事告诉了我弟弟,所以张老师的联系方式我不能删掉(闭包),因为我弟弟指不定哪一天就会要张老师联系方式。

函数执行的完整过程

开辟一片栈空间,根据作用域生成上下文

形参赋值

变量提升

代码从上到下运行

执行完毕后,判断有没有闭包,没有的话上下文销毁

垃圾收集机制(为什么闭包上下文不销毁?

怎么实现闭包上下文不销毁的?这个得从JS的垃圾收集机制开始讲。

js有两种垃圾收集机制,一种是引用计数(老版IE),还有一种是标记清除

引用计数(淘汰):  只要被引用就+1 ,引用它的变量又被赋值就-1(ie9之前的dom,bom)

存在问题:循环引用 比如dom引用js对象,JS对象(一般可以是闭包内绑定dom事件)又反过来引用dom,即使此时页面移除dom,dom也不会被回收,除非两个手动设置为null这就造成了内存泄漏

标记清除:垃圾收集器在运行时给内存中所有的变量加上标记,然后去掉环境中的变量以及被环境中变量引用的变量的标记(这也是为什么闭包存在的原用)。被标记的视为准备删除的变量.

正是因为外层上下文有内层上下文中某些东西的引用,所以内层上下文的标记不清除,在随后的垃圾收回操作中不被收回销毁。

练习题

1.函数传参本质
解析可参考:https://segmentfault.com/a/11...

 var ary = [1,2,3,4];
    function sum(ary) {// 私有的;
        ary[0] =100;
        ary = [];// 在JS中,遇到{}、[]都会开辟一个新的空间地址
        ary[0] = 10;
        console.log(ary)
    }
    sum(ary); // [10]
    console.log(ary);// [100,2,3,4]

2.特殊变量提升

var foo=1; 
function bar(){
    if(!foo){
        var foo=10; 
    }
    console.log(foo); 
}
bar(); //10

3.作用域、变量提升

console.log(a); 
var a=12; 
function fn(){
    console.log(a); //注意这里的a在本执行环境获取不到,根据作用域链搜索全局执行环境的a
    a=13;   //同理修改的也是全局执行环境的a
}
fn();   
console.log(a);     
// undefined 12 13
console.log(a); 
var a=12; 
function fn(){
    console.log(a); 
    var a=13;   
}
fn();   
console.log(a);     
// undefined undefined 12

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109630.html

相关文章

  • JS核心识点梳理——下文作用闭包this(中)

    摘要:引言满满的干货,面试必系列,参考大量资料,并集合自己的理解以及相关的面试题,对核心知识点中的作用域闭包上下文进行了梳理。本篇重点介绍闭包和。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 满满的干货,面试必bei系列,参考大量资料,并集...

    rottengeek 评论0 收藏0
  • JS核心识点梳理——下文作用闭包this(下)

    摘要:引言前面两篇文章介绍了上下文作用域闭包。这里我精心挑选了一些特别经典的面试题不定期更新,跪求收藏。闭包组这类题目还是挺简单的,我总结了几个要注意的地方有没有闭包如果有闭包,看创建了几个闭包。不要在脑子里想,每步的结果用纸和笔演算下 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 前面两篇文章介绍了上下文、作...

    XUI 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0
  • 好程序员Web前端培训入门之JS基础知识梳理汇总

    摘要:好程序员前端培训入门之基础知识梳理汇总,前端工程师是当前各大企业都比较稀缺的人才,薪资待遇和就业前景都很不错。作用域链的前端,始终是当前执行代码所在环境的变量对象。   好程序员Web前端培训入门之JS基础知识梳理汇总,Web前端工程师是当前各大企业都比较稀缺的人才,薪资待遇和就业前景都很不错。不论是专业还是非专业,有基础亦或是无基础,都想通过学习Web前端实现高薪就业。不过,学习要一...

    int64 评论0 收藏0
  • 好程序员Web前端培训入门之JS基础知识梳理汇总

    摘要:好程序员前端培训入门之基础知识梳理汇总,前端工程师是当前各大企业都比较稀缺的人才,薪资待遇和就业前景都很不错。作用域链的前端,始终是当前执行代码所在环境的变量对象。   好程序员Web前端培训入门之JS基础知识梳理汇总,Web前端工程师是当前各大企业都比较稀缺的人才,薪资待遇和就业前景都很不错。不论是专业还是非专业,有基础亦或是无基础,都想通过学习Web前端实现高薪就业。不过,学习要一...

    kviccn 评论0 收藏0

发表评论

0条评论

Andrman

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<