首页 > 大神求解答JavaScript函数实例的问题

大神求解答JavaScript函数实例的问题

为什么第一个图里的函数实例f1===f2就是假的。。第二个图里的函数实例f3===f4就是真的呢?还有什么是JS的函数实例呢?请大神指导一下小白


你仔细观察一下,第一个例子返回的是函数声明。也就是说,声明了2个同名函数,他们在堆内存中是不一样的。

第二个例子

因为aFunc_3有个函数自执行的括号,因此最后的结果是

var myFunc = function() {}
aFunc_3 = function() {
    return myFunc;
}

于是f3 === f4就很好理解了。他们指向了同一个函数。


你的第一个不相等是因为,你每执行一次函数,就返回了一个新的函数(也就是说内存上位置不同),所以肯定是不相等的,第二个相等是因为,这是一个自执行的函数,你的aFun3,也就是下面的这个函数

return function () {
    return MyFunc;
}

所以你在执行aFun3返回的是同一个函数,也就是MyFun
简单的可以将上面的两种情况等价为以下的两种情况:
第一个:

    var f1 = function () {},
        f2 = function () {},
        a = f1,
        b = f2;
    console.log(a === b);  // 必然是false啊

第二个:

    var f1 = function () {},
        a = f1,
        b = f1;
    console.log(a === b);  // true,a和b是指向同一函数

每次执行aFunc的时候,会创建一个aFunc的新的执行环境。然后执行环境的作用域链就是aFunc的[[scope]]。
与此同时,aFunc的活动对象也会push到执行环境的顶端。
aFunc的活动对象包括var声明的局部变量、function声明的函数、以及aFunc的形参。
这个MyFunc就是aFunc的活动对象,会在aFunc执行的时候创建。
所以每次执行aFunc都会创建一个新的MyFunc。
因此f1 与f2 是两个不同内存地址的函数,只是函数体(函数代码)相同而已。
所以f1 == f2为false。

----------------------- 分割线 -----------------------

第二个图中,aFunc3的右侧是一个立即执行函数,aFunc3的值即是立即执行函数的返回值。
在那个立即执行函数体内,注意return function (){return MyFunc;}这个匿名函数。
这个匿名函数在创建的时候,会将作用域链保存在内部属性[[scope]]中,这个[[scope]]如图:

然后匿名函数返回给了aFunc_3。
每次执行aFunc_3(即刚才那个匿名函数),会创建一个执行环境,它内部属性[[scope]]会初始化给执行环境的作用域链,函数的活动对象再push到作用域链顶端,因为此函数内没有var声明的局部变量、function声明的函数以及参数,就为空。
然后执行return MyFunc;,此时引擎会沿着作用域链往下找,找到MyFunc就返回。
注意:这是一个顺着作用域链找标示符MyFunc的过程,并没有产生新的函数。
所以所有aFunc_3执行后返回的函数都是当时那个MyFunc。
因此f3 == f4为true。


要搞清楚这个问题,涉及到几个概念
作用域
对象的比较方式
闭包

第一张图
每次调用,都会在外层函数的作用域中,重新定义内层函数并命名为MyFunc,然后return出来。所以,考虑到function也是个对象,代码简化为

function aFunc {
  var MyFunc = {}
  return MyFunc
}

又因为对象的===实际是比的内存地址

{} === {} // false,因为两边并不是同一个{}

第二张图
同理简化为下面的形式

var a = (function {
  var my = function (){}
  return function () {
    return my
  }
})()

立即执行函数表达式(Immediately Invoke Function Expression)返回一个获取闭包内变量的函数
此时,不妨再简化一下,所有作用域往上提一层,把my放在global,整个global可以看作一个大的“闭包”,a具有访问这个global“闭包”(作用域)内变量的能力

var my = function () {}
var a = function () {return my}

显然,无论调用多少次a,返回的都是同一个my


看了一楼的答案之后百度了下,涨姿势了。。。
现在我的理解,大概是这样的:

图1和图2的区别,主要就是关于JS的函数闭包和内存回收的问题。
图1类似于:

var f1 = function(){
    var f2 = function(){

    };
    return f2;
};

或者考虑的更极端一点,这样:

f1 = function(){
    f2 = function(){

    };
    return f2;
};

无论如何,每次执行f1函数,f2必然都会被重新赋值为一个新的函数,于是函数的返回值不相等。

图2是这样的:

var f1 = function(){
    var f2 = function(){

    };
    return function(){
        return f2;
    }
}();

更直观的理解就是:

var f1 = function(){
    return f2;
}

注意,每次执行f1函数,只执行这一句return f2;所以f2不是每次都变成新的函数。
另外,因为f1的返回值持有了f2的引用,所以f2一直在内存里,不会被销毁。
于是,函数的返回值都是f2。


何必解释得那样图文并茂,反而让人看不懂

“js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量一起保存起来,构建一个闭包,这些变量将不会被内存回收器所回收。”


1)每次aFunc()执行后返回一个函数对象都是不同的,所以f1和f2不相同
2)第二个片段aFunc_3指向一个立即执行函数执行后返回的函数,这个函数处在一个闭包环境中,每次执行总是返回闭包中的MyFunc函数,所以f3和f4是相同的
3)JS中定义的任何一个函数-无论通过声明语法声明的还是通过函数表达式声明的-都是函数对象的实例,函数也是有原型的-Function

【热门文章】
【热门文章】