请教个js执行顺序问题?

var obj = {};
(function(obj){
    obj.m = function(){
      console.log(ooo);
    };
    var ooo = {};
 })(obj);
obj.m();//可以打印出 ooo {}

问题是这个ooo不是声明在obj.m这个方法后面吗,怎么可以打印出。本来以为是打印出underfined呢?

阅读 2.8k
7 个回答
function foo() {
    console.log(str);
}
var str = "aaaaa";
foo();

你说这段代码输出undefined还是aaaaa
只要调用的时候有值就行了

这跟变量提升没有关系,涉及到的知识是闭包和作用域。

闭包是一个函数,它能够记住创建它的那个作用域,并且在那个作用域外调用时仍然能够访问那个作用域里的变量。

分析你的代码:

var obj = {};
(function(obj){//作用域,命名为Scope
    obj.m = function(){
        //obj.m是一个声明在Scope中函数,记住了当前作用域Scope。
      console.log(ooo);
    };
    var ooo = {};//声明在Scope中
 })(obj);
obj.m();//当obj.m在Scope中调用时,根据闭包的定义,自然可以打印出 ooo {}

至于为什么不是打印undefined,是因为执行obj.m();时,Scope中的ooo已经完成了赋值操作。
另一方面,没有报错Uncaught ReferenceError:ooo is not defined;也是能证明obj.m确实持有对Scope中的ooo的引用,也就是形成了闭包。

我看了一下你的评论,觉得我们理解的闭包概念不一样。我认为的闭包是obj.m,而你认为的闭包是(function(obj))(obj)这个IIFE。emmm,我觉得我是对的。

变量的声明会被提升.

这样理解吧。obj.m = function(){}产生了一个闭包,因为方法体访问了ooo的引用。那么ooo这个引用显然是个动态的,根儿上来说就是个地址,这个地址指向的空间可能在定义obj.m的时候是个空的(undefined),但是随着程序的执行ooo被赋值了,地址指向的空间有东西了,自然也就能打印出东西了

大哥,当你执行obj.m()这个方法时,我ooo早就赋值了好吗。
除非这样写

var obj = {};
(function(obj){
    obj.m = (function(){
      console.log(ooo);
    })();//这里改成自执行,这才是ooo还没赋值, 你那个是在代码末尾执行,我ooo已经赋了值了
    var ooo = {};
 })(obj);
var obj = {};//1
(function(obj){//2
    obj.m = function(){//3
      console.log(ooo);//6
    };
    var ooo = {};//4
 })(obj);
obj.m();//5

js的变量提升

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题