一道关于作用域,this,立即执行函数的题目

50 阅读2分钟

有几个值得注意的知识点:

  • 形参也是私有属性的一种;
  • 立即执行函数的this指向一般是window;
  • 立即执行函数,与普通函数不同的是声明和定义后,会立即运行一次函数,不像普通函数一样声明过后是一堆代码字符串等待执行;
  • 上一级作用域,看的是函数声明的地方而不是执行的地方
  • 留意对象初始化过程,在对象里面的各种函数未执行完成之前使用该对象的任何属性都会报错(因为还未完成嘛)
var n = 2;
var obj = {
    n: 3,
    fn: (function(n) {
        n *= 2;
        this.n += 2;
        var n = 5;
        return function (m) {
            this.n *= 2;
            console.log(m + (++n));
        }
    })(n)
};
var fn = obj.fn;
fn(3); // 9
obj.fn(3); // 10
console.log(n, obj.n); // 8, 6

结合图文来看

  • 全局作用域下,变量提升n,obj,fn
  • 全局作用域下,n与值2关联;obj的值是一个对象,开辟一个堆内存AAA
  • 初始对象AAA,属性n与值3关联,方法fn的值是一个立即执行函数,开辟一个BBB的堆内存
  • 立即执行函数BBB,形参赋值,因为立即执行函数的this是window,因此形参值是2,即私有变量n值为2;
  • 立即执行函数BBB,一匿名函数,开辟一个CCC的堆内存,声明并定义,CCC里有代码字符串;
  • 立即执行函数BBB,代码自上而下执行,n*=2;n是私有变量,n的值改为4;
  • 立即执行函数BBB,this.n+=2,因为立即执行函数的this是window,因此全局变量n的值改为4;
  • 立即执行函数BBB,因为形参赋值时已定义n,因此var n没有变量提升,私有变量n值改为5;
  • 初始对象AAA,立即执行函数已执行完毕,obj对象初始化完成(在此之前obj的值都是undefined,在此之前使用obj.n都会报错);
  • 全局作用域下,fn与堆内存CCC关联
  • 全局作用域下,执行fn(3),运行堆内存CCC,形参赋值,m=3,this.n*=2,fn的this指向window,因此全局变量n的值改为8,输出m+(++n),由于堆内存CCC没有私有属性n,往上级作用域找,在堆内存BBB找到私有变量n且值改为6,因此m+(++n)结果为3+6=9
  • 全局作用域下,执行obj.fn(3),运行堆内存CCC,形参赋值,m=3,this.n*= 2,obj.fn(3)的this执行obj,因此obj的属性n的值改为6,输出m+(++n),由于堆内存CCC没有私有属性n,往上级作用域找,在堆内存BBB找到私有变量n且值改为7,因此m+(++n)结果为3+7=10
  • 全局作用域下,输出全局变量n为8,obj.n为6

(图画得有点乱,见图2) 初始化对象的过程.png

初始化对象的过程2.png