闭包这个词对不少前端开发人员来讲既熟悉又陌生,熟悉是由于不少人都用过闭包,可是用的时候不知道闭包,陌生是由于并不理解闭包,接下来这篇文章将会从多方面介绍闭包前端
闭包是怎么定义的呢?当函数能够记住并访问所在的词法做用域时,就产生了闭包,即便函数在当前词法做用域以外执行。来看一个具体例子:面试
function foo () {
var a = 2
function bar () {
console.log(a)
}
return bar
}
var baz = foo()
baz() //2
复制代码
函数bar的词法做用域能够访问foo的内部做用域,而且bar在被做为返回值赋值给baz执行时,bar函数在定义时的词法做用域之外的地方被调用,依然能够访问foo函数的内部做用域变量a,这就是闭包bash
如今让咱们来看为何闭包能够在定义的词法做用域外记住而且访问定义时的词法做用域的变量,想要一探究竟,先来看一个简单的例子来函数的执行过程:闭包
function foo (a) {
console.log(a)
}
foo (a)
复制代码
function foo () {
var a = 2
function bar (b) {
console.log(a + b)
}
return bar
}
var baz = foo()
baz(3) //5
复制代码
说到闭包相关的问题,最典型的就是变量和this指向这两类问题。函数
function test () {
var result = new Array()
for (var i = 0; i < 6; i++) {
result[i] = function () {
return i
}
}
return result
}
复制代码
function test () {
var result = new Array()
for (var i = 0; i < 6; i++) {
result[i] = (function () {
return i
})()
}
return result
}
复制代码
将闭包直接改为一个自执行函数,自执行函数自己是没有变量做用域的,所以会使用外层函数的变量做用域,这样也能达到咱们想要的效果ui
var name = "window"
var obj = {
name: "object",
getName: function () {
return function () {
return this.name
}
}
}
console.log(obj.getName()())
复制代码
上面这段js代码的this.name的返回值是window,这是为何呢?按照上面写到的,此匿名函数在执行过程当中,它的做用域会包含三部分:自身的活动对象、getName函数的活动对象和全局的变量对象,同时每一个活动对象自动取得两个特殊的变量:this和arguments,可是内部函数在查找this时是没法直接访问外部函数的this变量,所以会沿着做用域链去查找全局变量中继续查找,若是想要取外部函数中的this取值也很简单,只须要向下面代码这样:this
var name = "window"
var obj = {
name: "object",
getName: function () {
var that = this
return function () {
return that.name
}
}
}
console.log(obj.getName()())
复制代码
将this赋值给一个变量,内部函数是能够访问外部函数变量的,这样就解决了spa
闭包是一个容易混淆不清的概念,这篇文章对闭包的定义、执行、常见问题作了简单的介绍,但愿经过这篇能对你们理解和使用闭包有所帮助。若是有错误或不严谨的地方,欢迎批评指正,若是喜欢,欢迎点赞。code