Javascript中自我调用功能的范围

时间:2010-11-23 22:11:17

标签: javascript

为什么函数内部的自调用函数不能获得JavaScript中外部函数的作用域?

var prop = "global";

var hash = {
    prop: "hash prop",
    foo: function(){
        console.log(this.prop);
        (function bar(){
            console.log(this.prop);
        })();
    }
};

var literal = {
    prop: "object"
};

hash.foo();
// hash prop
// global

hash.foo.call(literal);
// object
// global

看起来改变外部函数的范围对内部自调用函数的范围没有影响。

PS:问题不在于如何改变内部功能的范围。但是,在“Javascript语言”视角下,正确的解释是什么?默认情况下,所有自执行函数都具有“全局”范围吗?如果是这样,为什么?

2 个答案:

答案 0 :(得分:7)

您的问题是this及其引用的内容:

foo: function(){
    console.log(this.prop);
    (function bar(){
        console.log(this.prop);  <--- this does not reference to foo here, but instead it refers to the window object
    })();
}

您需要保留对外this

的引用
foo: function(){
    console.log(this.prop);

    var that = this;
    (function bar(){
        console.log(that.prop);  <--- tada!
    })();
}

<强>更新
一些解释。这是关于JavaScript在调用函数时如何确定上下文的。

function Test() {
    this.name = "Test";
    this.bar = function() { console.log("My name is: "+ this.name);}
}

function Blub() {
    this.name = "Blub";
    this.foo = function() { console.log("My name is: " + this.name);}
} 

var a = new Test();
var b = new Blub();

// this works as expected
a.bar(); // My name is: Test
b.foo(); // My name is: Blub

// let's do something fun
a.foo = b.foo; // make an educated guess what that does...

a.foo() // My name is: Test

咦?我们不是在引用Blub的method吗?没有,我们没有。我们引用了Blub的未绑定function

JavaScript绑定.(点),并根据它确定this的值应该是。

由于你没有在一个对象上调用你的匿名函数(因此没有.),它将使this引用全局对象,在浏览器的情况下,它是窗口对象

另一个例子(人们可能认为这会起作用):

var str = "Hello World";
var ord = str.charCodeAt; // let's make a little shortcut here.... bad idea

ord(0) // no dot... 

而不是str中的字符代码,我们得到全局对象中的字符代码,当然这不是字符串,因此charCodeAt调用toString会导致"[object DOMWindow]" { {1}}

答案 1 :(得分:1)

当您调用内部函数时,您没有将任何对象应用为this上下文,因此默认情况下this设置为window。如果你想用与外部函数相同的this调用闭包,你必须这样做:

(function bar(){
    console.log(this.prop);
}).call(this);

或者:

var that = this;
(function bar(){
    console.log(that.prop);
})();