乐趣区

JS核心知识点梳理上下文作用域闭包this中

引言

满满的干货,面试必 bei 系列,参考大量资料,并集合自己的理解以及相关的面试题,对 JS 核心知识点中的作用域、闭包、this、上下文进行了梳理。上一篇介绍了作用域和上下文。因为感觉这两个概念互相纠缠,上下文的生成会依赖作用域规则。本篇重点介绍闭包和 this。

this

先介绍 this,因为我觉得 this 最简单了,掌握住分析的方法,依照方法去分析,毫无难度。

为什么引入 this

因为我们解耦,为什么要解耦?因为我们要复用!
举个例子:我费了九牛二虎之力写了一个方法,可以对某个数组 a 进行复杂的操作

var a = [xxx,xxx,....]
function foo (){
  a xxx // do something to a
  xxx a  // do something to a
}

这个方法只能 a 用 耦合性太强。当其他数组 b 想用这个方法的时候由于方法里面的 操作对象固定是 a 导致失败。
当然我也不能写成 b,因为如果数组 c 要用难道我们再改成 c?
怎么办,显然这个操作的对象不能是固定的,应该说最好是一个变量,谁调用,这个变量就是谁。
this 就这么产生了!所以说 this 的可变是业务的需要,我们要的就是它的可变。当然你要是掌握不了它的变化规则,那么对你来说引入 this 就是一场灾难了。

this 的规则

总原则: 函数中的 this,指的是当前函数的执行主体;谁让函数执行的,那么 this 就指向谁

  • 在全局作用域下,this 指向 window;
  • 函数体中的 this,看函数执行前有没有 ”.”, 如果有,那么点前面是谁,this 就指向谁;如果没有“.”,那么会指向 window;
  • 如果给元素的事件行为绑定方法,那么方法中的 this,就会指向当前被绑定的那个元素;
  • 回调函数中的 this 指向 window;
  • 自执行函数中的 this 永远指向 window;

改变 this

apply call bind 可以改变 this

问题来了,为什么要改变 this?

还记得我之前说的引入 this 是为了进行更好的复用吗?
js 里面没有类,但是通过原型、继承 js 在努力模仿类。同一个类当然能通过继承复用代码,不同类不继承的情况下怎么复用呢?通过改变 this。
举个例子,Array 类有 reverse 方法。只要是数组,都继承了 Array 的 reverse 方法,可以直接调用。

[1,2,3].reverse()  //[3,2,1]

现在有个类数组 arguments, 由于不属于 Array 类,没有办法继承 reverse 方法,但是我就是想用,咋办?改变 this

Array.prototype.reverse.call(argumengts)

闭包

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的 函数 。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由 函数和与其相关的引用环境组合而成的实体。wiki

闭包这个东西咋说呢,不同的程序员,不同的资料都有不同的理解。你把它理解为一个函数,也可以把它理解为函数 + 执行环境。

我们这里不纠结闭包的定义。而是关注闭包的现象,应用,再结合相关面试题去攻克它,最后谈一下我对闭包的思考。

现象

话说了一箩筐,你倒是给我上代码呀 …..
各位看官息怒,小的再多说几句

之前我们说过了,函数执行,生成执行环境。函数执行完,销毁执行环境。嗯,听上去很正常,不用的东西就销毁嘛。

但是如果函数执行完,该函数上下文还用用怎么办,有用的东西肯定不敢销毁了。这个就是闭包的现象,那么能引起这个现象的鄙人就把它理解为闭包!

function foo () {
    var a = 1
    return function bar () {
        a++
        console.log(a)
    }
}
var b = foo() // 函数执行完,我就问你 foo 的上下文你敢销毁吗?b()  //  2
b()  //  3

大家看 foo 执行完的结果赋值给了 b, 也就是函数 bar 赋值给了 b,未来我可能让 b 执行的,也就是让 bar 执行,所以我需要保证 bar 能访问上下文不被销毁。bar 能访问的上下文实际上是 foo 执行时候的上下文。所以 foo 执行完以后上下文不会被销毁,会继续存在。

我的理解是 函数向外层作用域暴露出了一个内部引用,那么就存在闭包现象(真的没必要纠结闭包到底是啥,是函数?内部整体?是 xxx?`。

作用与应用

作用 1:保存变量

应用: 函数柯里化

var add = (a)=>(b)=> a+b
add(2)(3) //5
 

优点:延迟执行,提前传参,逼格高

作用 2:保护变量(不受污染)

应用: 单例模式

 //jQ 源码
 (function(){var jQuery=function(){//jq 代码}
      window.$=window.jQuery=jQuery;  // 这个通过 window 对象暴露给外面,根 return 的暴露是一个意思
   })()
// 函数执行完了,里面的引用暴露给外面了,所以上下文不销毁

优点:变量和函数都写到立即执行函数里面了,避免了污染外层作用域

优缺点

闭包无处不在,也许你不经意就写了个闭包。

需要注意的是,由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在 IE 中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

总结

本篇详细介绍了闭包和 this 的来源,规律,应用。由于篇幅有限,将在下一篇中会结合各大公司面试题来巩固这些知识,希望给大家带来帮助。

退出移动版