<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 了解闭包前,要知道垃圾回收机制,超级简单来说,就是window对象上能
// 访问到的变量会被存储下来,称作可达对象,没被引用的会被回收。
// 函数执行前会在执行上下文创造vo对象,可以直接理解成一个对象。
// 分为go,ao。go.window=this,所以window就是go的一个引用,
// 可以直接理解成go就是window。ao是函数内部秘密创建的,无法访问到。
// 比如在全局作用域下,vo -> go。在普通函数内vo->ao。
// 下面来分解这段代码。
function foo(params) {
var name = 'foo'
function bar() {
console.log(name);
}
return bar
}
var fn = foo();
fn()
// go全局对象,就是window。
var Object_go = {
foo: foo_fn,//函数是在堆内存里面的,所以是一个地址(指针),我这里用对象代替
fn: undefined,
}
// 可以理解成foo函数在堆内存中的存储的表现形式
var foo_fn = {
scope: Object_go,
//作用域链,可以理解成原型链一样的东西。比如一个对象找属性都是一层一层往上找的,
// 作用域链差也是。先从自身的ao对象上查找,再找作用域连上的。
content: `var name = 'foo'
function bar() {
console.log(name);
}
return bar`
}
// 执行阶段到var fn = foo()这一段就形成了闭包的引用。
//碰到 var fn = foo();这一句时执行函数,执行上下文栈之类的就不讲了。就按照这种简单的方式理解吧。
// 创建ao对象。foo_Object_ao
var foo_Object_ao={
name:'foo',
bar:bar_fn,
}
var bar_fn={
scope: foo_Object_ao ,
content:'console.log(name);'
}
// var fn = foo() 赋值操作。
var Object_go = {
foo: foo_fn,//函数是在堆内存里面的,所以是一个地址(指针)
fn: bar_fn,
}
// 现在来看可达对象的那里的理解。Object_go全局对象。也就是window。
// Object_go.fn -> bar_fn bar_fn.scope->foo_Object_ao
// 这样就形成了引用。也就是这样为什么foo()执行后,bar函数还能访问name,而没有被回收的原因。
</script>
</body>
</html>