我们先来看一道题,然后再来分析其思路。
var num = 10;
var obj = {num:20}
obj.fn = (function (num){
this.num = num * 3
num++
return function (n){
this.num + = n
num++
conole.log(num)
}
})(obj.num)
var fn = obj.fn
fn(5)
obj.fn(10)
console.log(num,obj.num)
解题思路分析:
1. 整个代码执行的过程中因为都是var 声明的变量和方法所以不会存在变量提升的问题;
2. 我们再来看栈内存中存在哪些【变量】【基本数据类型】和【指针】
变量 var num; var obj; var fn; 这三个变量。
基本数据类型: var num = 10
指针需要指向的比如 obj 当做是 0x001 指针; fn 指向的0x003指针
3. 我们再来看一下堆内存中都会存放哪些引用数据类型:【对象 函数 数组 class类】
3.1 先来分析obj这个堆内存空间存储的数据
0x001 指向的对象obj = {num:20} ,代码在执行的过程中会重新给obj添加一个属性为fn的
方法,这时候obj会多一个属性为fn的这个方法,此时在堆内存中会重新生成一块空间
0x003来存储立即执行函数返回的值。 此时的obj就变成了 obj = {num:20, fn:0x003}
3.2 把立即执行函数存储在0x002空间
0x002 这块空间是用来干嘛的呢,这个块空间是用来存储立即执行函数的(function ...)()
疑问点? 为什么obj.fn指向的不是0x002这个立即执行函数,而是0x003这个空间呢。其
实obj.fn存储的是立即执行函数的返回值也就是return里面的这个函数(0x003)。
3.3 0x003存储的便是立即执行函数,执行以后返回的结果了也就是返回的函数。
3 我们再来看一下代码具体执行的过程:
var fn = obj.fn // 这段代码返回的结果是 立即函数执行的返回的结果,我们再来看一下立
即函数执行的过程, 立即函数执行的代码。this.num = num * 3 num++;
因为立即函数在执行的过程中把全局的参数obj.num = 20作为参数 所有立即执行函数产
生私有变量20, this.num = num*3, 这是把全局的num进行修改 变为了 60,这时候全局
下的var num = 60。 接下来的代码执行 num++, 此时是私有变量num进行++,由之前的
20变为了21。 私有的num在后期函数执行后因为被fn占用所以变量不会被释放。
4 fn(5) 相当于是把return里面的小函数执行了。
return function (n){
this.num + = n
num++
conole.log(num)
}
这里把5作为参数传递给了function这个函数。 this.num += n。 改变全局的num由之前的
60目前已经变为65了。 num++,因为自己的作用域么有num,所以只能去上级作用域中
找,上级作用域的num由21现在变为了22。 所以console.log(num) //输出的结果为22
5 obj.fn(10)这里我们继续分析,这时候相当于把参数10传递给了return返回的这个函数了。
全局的参数num依旧没有发生改变还是65。而闭包私有的变量此刻由21变为22。 接着执
行return返回的函数 this指向obj 此刻obj的num由20变为了30。 闭包私有变量也变为了
23, 所以结果是23。
6 console.log(num,obj.num) // 65 30
以下是图表分析: