var outwrap = function(){
            this.heihei = function(){
            };
            this.heihei.prototype = {
                b: (this.bb = function(){
                    var md = this;
                    return function(){
                        return md;
                    }
                })()
            };
        };
        var o = new outwrap();
        alert(o.bb);
        var h = new o.heihei();
        alert(h.b() == window);h.b() == window结果为true,非常疑惑,为什么h.b()的结果不是o,而是window呢,哪位高人帮忙解惑一下,谢谢

解决方案 »

  1.   

    参考如下代码:
    function f() {
            return this;
    }alert(window == f()); // true
    function f() {
        this.alert("hello");
    }f();从测试的结果看:函数中的this是window对象。
      

  2.   

    你贴的代码,我都明白,都是this的一些基础按照ecma标准的说法,函数中的this是由函数的调用者确定(Reference Type 是另外一种情况).
    在我贴的代码中this.bb的this指向了实例化后的outwrap对象,
    也就是说匿名函数的调用者的this指向了实例化后的outwrap对象,那么按照我对ecma标准的理解,函数中的md变量应该是指向实例化后的outwrap对象,而不是window
      

  3.   

    你连续利用了两个new 操作。你的this....
      

  4.   

    <script language='javascript'>
    ddd="ccccccccc";
     var outwrap = function(){ 
      this.ddd="ddddd";
      this.heihei = function(){ }; 
      this.heihei.prototype = { 
      b: (this.bb = function(obj){
       var md = obj; return function(){ alert( md.ddd); } }
      )(this) 
      }; 
      };
       var o = new outwrap(); alert(o.bb); var h = new o.heihei(); h.b();
    </script>
    把结果贴给你楼主可以自己分析一下区别是什么
      

  5.   

    我故意连用两个new的,原因嘛,就是说明this.bb的this
      

  6.   


    谢谢你的解答,但是还是不明白为什么md会指向window,如果知道的话,请赐教,非常感谢
      

  7.   

    h.b返回的是一个匿名方法,调用的时候相当于直接调用在页面上定义的方法
    function b(){}h.b() 并不是其他的对象调用了这个方法,而是window这个对象相当于
    window.(function(){});所以在方法内部的this指向的是window
      

  8.   

    非常感谢你的指点,
    但是对于下面这段代码如何解释呢,此时已经不是匿名函数了,但this依然指向window            var outwrap = function(){
    var fnName = null;
                this.heihei = function(){
                };
                this.heihei.prototype = {
                    b: (function fnName(){
                        var md = this;
        //结果为[object Window]
        alert(this);
                        return function(){
                            return md;
                        }
                    })()
                };
            };
            var o = new outwrap();
            var h = new o.heihei();
    //结果为true
    alert(h.b() == window);
      

  9.   

    楼主多找些JavaScript变量作用域的文章看一下。它们运行在被定义的空间,而不是调用的空间。
      

  10.   

    非常感谢你的指点话是这么说没错,但是我认为:
    1.这句话对其他变量有用,但对this却没有意义. ecma上说"this是由caller来决定的"的,我也是这么认为的
    2.重新修改了代码,修改了定义的位置,把原本全局的匿名函数改成了局部变量,但结果依旧,代码如下        var outwrap = function(){
                var aa = function(){
                 var fn = function(){
                 //结果[object Window]
                    alert(this);
                };
                 (fn)();
                };
                new aa();
            };
            var o = new outwrap();
      

  11.   

    var a = 'window';//window域的a
    var outwrap = function(){
    var this_of_outwrap_init = this;
    this.a = 'outwrap';//outwrap域的a
        var aa = function(){
            var this_of_aa_init = this;
            this.a = 'aa';//aa域的a
            var fn = function(){
                //结果[object Window]
                //alert(this);
             alert(this.a);
    };
            fn();//函数直接执行,内部的this,是哪来的呢?只好转到window域去了。输出window
            fn.call(this_of_outwrap_init)//this来自outwrap的实例化对象,输出outwrap
            fn.call(this_of_aa_init)//this来自aa的实例化对象,输出aa
        };
        new aa();
    };
    var o = new outwrap();
      

  12.   

            var outwrap = function(){
                this.heihei = function(){
                };
                this.heihei.prototype = {
                    b: (this.bb = function(){
                        var md = this;
        alert(this)
                        return function(){
                            return md;
                        }
                    })()
                };

            };

            var o = new outwrap();
            alert(o.bb());
            var h = new o.heihei();
    alert(o.bb())
            alert(h.b());1:this -- [object Window]2: o.bb()--[object Object]3: this-- function (){return md;}4:o.bb()--[object Object]5:this-- function () {return md;}6:h.b()--[object Window]调用h.b() 实际就是返回mdmd==?第一次实例化时,就定义了,md==[object Window]
      

  13.   

    看了下其实出现你的问题最根本的地方是:
    <script language='javascript'>
    dd="1111";
                var outwrap = function(){
                this.dd="2222";
                alert(this.dd);
             (function() {
    alert(this.dd);
        })();//匿名函数
             };
             var o = new outwrap();
    </script>
    经测试此"匿名函数"中变量的作用域是在window上,我认为这个调用匿名函数其实就是调用一个全局函数如同<script language='javascript'>
    dd="1111";
                var outwrap = function(){
                this.dd="2222";
                alert(this.dd);
             (function() {
    alert(this.dd);
        })();
        //cc();
             };
             function cc(){
             alert(this.dd)
             }
             var o = new outwrap();
    </script>
      

  14.   


    this始终指向调用它的对象,这是不错的!
    <script type="text/javascript">
    var a = function(){
    alert(this.a);
    };
    a();var b = function(){
    this.b = 'inner b';
    alert(this.b);
    };
    b();
    </script>
    其实你会发现,this也是可以通过作用域链来找到的!
      

  15.   

    (this.bb = function(){
                        var md = this;
                        return function(){
                            return md;
                        }
                    })()相当于
    (function(){
                        var md = this;
                        return function(){
                            return md;
                        }
                    })()
    是创建一个函数运行,此时并没有把这个函数赋值给this.bb,所以函数是window的一个属性(var创建全局变量会直接给window当属性,function也是),this直接指向window,赋值后的this.bb在运行,this就会指向o。如果单纯是一个变量的话就不会有问题了
      

  16.   


    var outwrap = function(){
        this.heihei = function(){
        };
        this.heihei.prototype = {
            b: (this.bb = function(){
                    // here this is window
                    return function(){
                        return md;// so return window
                    };
                })()
        };
    };
    /*
    这一步,对象o具有以下属性和方法
    o.heihei    类型:构造函数heihei的引用
    o.bb        类型:匿名函数function(){var md = this;return function(){return md;}}的引用首先要知道:
    任何立即执行的闭包【(function(){...})()的形式】,他的函数体内的this始终指向window经过了这一步的执行,b方法目前就是匿名函数
    function(){
        return window;//(也就是md)
    }
    的引用了。(这也是后来你执行h.b()而返回window的原因)*/
    var o = new outwrap();
    /*
    这一行代码相当于输出函数function(){var md = this;return function(){return md;}}的函数体
    */
    alert(o.bb);// 返回匿名函数
    /*
    你可以用下面的代码区测试o.bb到底是什么
    */
    // test
    alert(o.bb());// 返回 function(){return md;}
    alert(0.bb()());//返回 window对象,原因参见上面的注释(闭包的原因)/*
    这一行代码,就是实例化构造函数outwrap的实例对象h的一个属性:heihei
    */
    var h = new o.heihei();
    /*
    根据上面的分析,我们知道,b对象的值实际上在heihei实例化之前已经确定了,就是闭包立即执行后的结果:
    function() {
        return md;// 这里就是window
    }
    的引用了。所以h.b()便返回window了。*/
    alert(h.b() == window);
      

  17.   

    看了Objector的回复,我明白我的问题所在了:“首先要知道:任何立即执行的闭包【(function(){...})()的形式】,他的函数体内的this始终指向window”,我想原因应该就和前面几位说的一样,是因为这个匿名函数是一个匿名的全局变量,非常感谢各位不过好像全局匿名的函数如此,局部的非匿名函数还是如此,这是为什么呢?
    ----------------------华丽的分割线,以下说的都是局部的非匿名函数----------        var outwrap = function(){
             //局部变量aa
                var aa = function(){
                 //局部变量fn
                 var fn = function(){
                 //结果[object Window]
                    alert(this);
                };
                 (fn)();
                };
                //局部变量bb
                var bb = new aa();
            };
            var o = new outwrap();foolbirdflyfirst 在 12楼对此所说的“函数直接执行,内部的this,是哪来的呢?只好转到window域去了。输出window”,这又是为什么呢?
    按我的理解,此时的scope chain应该是:bb->0->window,作用域怎么会直接转到window呢
      

  18.   

    sorry,不是'直接转',是本域找不到的变量,转到window域去找.
    this并不在作用域链里查找,和使用到的变量要在作用域链中查找是不一样的var fn = function(){
      var a = 1;
      (function(){
          alert(a);//1
          alert(this) //window 
       })()
    }
    fn();
      

  19.   


    这种特性是“闭包(Closure)”的特性,而不是匿名函数的特性~ 只是利用闭包来解决问题的时候通常结合匿名函数来的。
      

  20.   

    To 20 楼Objector:不好意思,我表述有问题,我用的语句是“全局匿名的函数”,我本意是想强调“全局”2字To 19 楼foolbirdflyfirst:又是我的表述有问题.........以下是我对自己在18楼贴的代码的理解:
    执行var bb = new aa();也就是执行aa函数对象的[[constructor]],
    但[[constructor]]与普通函数有一个区别:
    1.对于普通函数,调用者会把自己的[[scope]](也就是this)参数传递给被调用者,于是被调用者就知道了this指向谁2.但对于构造函数,却不是这样:
      2.1如果在[[constructor]]内部出现了var fn = function(){}; 那么[[constructor]]不会对fn的[[scope]]赋值,也就是说fn的[[scope]]为null, 按照规范当[[scope]]为null时,会把[[scope]]置为window.
      2.2或许你会问this.ooxx = funcion(){};这种情况是怎么会事,这很大程度上是依靠Reference Type上述是我对这个情况的理解,没有看到相关的权威资料,但感觉都能说通,所以对这种说法还是比较自信的
      

  21.   

    To 20 楼Objector:不好意思,我表述有问题,我用的语句是“全局匿名的函数”,我本意是想强调“全局”2字To 19 楼foolbirdflyfirst:又是我的表述有问题.........以下是我对自己在18楼贴的代码的理解:
    执行var bb = new aa();也就是执行aa函数对象的[[constructor]],
    但[[constructor]]与普通函数有一个区别:
    1.对于普通函数,调用者会把自己的[[scope]](也就是this)参数传递给被调用者,于是被调用者就知道了this指向谁2.但对于构造函数,却不是这样:
      2.1如果在[[constructor]]内部出现了var fn = function(){}; 那么[[constructor]]不会对fn的[[scope]]赋值,也就是说fn的[[scope]]为null, 按照规范当[[scope]]为null时,会把[[scope]]置为window.
      2.2或许你会问this.ooxx = funcion(){};这种情况是怎么会事,这很大程度上是依靠Reference Type上述是我对这个情况的理解,没有看到相关的权威资料,但感觉都能说通,所以对这种说法还是比较自信的
      

  22.   

    印象中ecma对于this强调了两三次
    只是我在23楼所说关于“[[constructor]]不会对内部的函数提供[[scope]]”的猜想好像没有什么权威资料, ecma并没有类似这样的称述, 不知有没有高手看到过相关资料能够证明或者反驳这一点的
      

  23.   

    其实把代码写正常一点就明白了
    var outwrap = function(){
    this.heihei = function(){
    };

    function bb(){
    var md = this;
    return function(){
    return md;
    }
    }

    this.bb = bb

    this.heihei.prototype = {
    b: bb()
    };
    };可见后面
    b: bb()
    这里bb运行时里面的this显然就是window了
      

  24.   

    var b = { name:"b" };
    window.name = "window";function f(){
    alert(this.name)
    }(b.f = f)();b.f = f;
    b.f();这样应该更明白了
    注意两者的区别
      

  25.   

    (b.f = f)();
    相当于
    b.f = f;
    f()
    而不是
    b.f = f;
    b.f();
      

  26.   

    谢谢,其实在1楼贴出来的代码会弹出window,原因已经明确了:因为闭包中出现了全局函数但由此引申出来的问题: 见18楼代码,以及 25楼的猜测 
      

  27.   

    scope chain跟this无关
    this只跟调用函数的对象有关
    如果没有这个对象 一律看成是window
      

  28.   

    不是this是window就是全局函数
    作用域看scope chain
    this看谁调用函数
    两者是分开的
      

  29.   

    lz要看ecma的话在这里10.2.3 Function Code
    ..............
    • The caller provides the this value. If the this value provided by the caller is not an object (including the case where it is null), then the this value is the global object.
      

  30.   

    我说的全局函数,是指1楼代码中“this.bb = ”后面那坨函数,
    你说不是全局的,那么你觉得他是谁的局部函数??
      

  31.   

    我认为cloudgamer兄这句话说在点子上了
      

  32.   

    简单点说吧,如果你的function是一个对象,即他没有return,那么它里面的this就是自己。如果它是一个方法或者函数,即,有return,那么它里面的this就是运行时对象--在楼主的例子里面就是window,在其它情况下可以是一个button一个image或者其它
      

  33.   

        };
            var o = new outwrap();
            alert(o.bb);
            var h = new o.heihei();
            alert(h.b() == window);
    有点不懂
      

  34.   

    sorry,我刚才打错了
    清不要封号!
      

  35.   

    理解了一点点  thanks 高手们
      

  36.   

    When a function is not the property of an object, then it is invoked as a function:var sum = add(3, 4);    // sum is 7
    When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language. Had the language been designed correctly, when the inner function is invoked, this would still be bound to the this variable of the outer function. A consequence of this error is that a method cannot employ an inner function to help it do its work because the inner function does not share the method's access to the object as its this is bound to the wrong value. Fortunately, there is an easy workaround. If the method defines a variable and assigns it the value of this, the inner function will have access to this through that variable. By convention, the name of that variable is that:// Augment myObject with a double method.myObject.double = function (  ) {
        var that = this;    // Workaround.    var helper = function (  ) {
            that.value = add(that.value, that.value)
        };    helper(  );    // Invoke helper as a function.
    };// Invoke double as a method.myObject.double(  );
    document.writeln(myObject.getValue(  ));    // 6