OO javascript – 构造函数中自执行函数的上下文/范围

在构造函数中使用自执行anon函数时,我有一个关于上下文/范围的快速问题.

请注意以下工作代码:

function Foo() {
    this.height = 10;
    this.width = 10;
    this.init = function() {
        this.create();
    };
    this.create = function() {
        alert('test');
    };
} 

var span1 = new Foo();
span1.init();

警报显示为预测.但是,我不想在底部调用span1.init.我宁愿让Constructor函数中的init函数自动执行.这将给我如下代码:

function Foo() {
    this.height = 10;
    this.width = 10;
    this.init = (function() {
        this.create();
    })();
    this.create = function() {
        alert('test');
    };
} 

var span1 = new Foo();

然而,在一些谷歌搜索后,似乎使用自我执行给它全球范围,因此this.create在全球意义上不存在.

我想我必须做一些电话/申请,但我不确定究竟是什么或在哪里.

任何指针都将非常感激.

干杯,
广告.

最佳答案 阿迪,你在这个例子中所做的事情有两个问题.

第一个问题是在立即调用的函数内部,这个===窗口.

第二个问题是这些都是函数表达式.
因此,它们都是在线定义的.

function makeIt () {
    this.a = function () { this.b(); };
    this.b = function () { console.log("B"); };
}

由于后期静态绑定,这将起作用.
这意味着在a内部,浏览器在调用函数之前不知道它指的是什么.然后它会在那个确切的时刻找到它所引用的对象.

否则,就像分配变量一样:

function makeIt () {
    this.a = this.b;
    this.b = "George";
}

在那里你会得到一个错误.
为什么?只是因为当你分配a时,b还没有值.

function Foo () {
    this.init = (function (context) { context.change(); }(this));
    this.change = function () { doStuff(); };
}

那么这个陈述有什么问题呢?
嗯,立即调用函数是立即调用的函数.
这意味着即使我们已经解决了这个问题,也可以将this的值作为参数传递给内部范围……

……我们要求它运行一些尚不存在的东西.

function Foo () {
    this.change = function () { doStuff(); };
    this.init = (function (context) { context.change(); }(this));
}

这应该工作得很好.
…然而…

…为什么你会这么做呢?
就像在,当你想要它自动构建时,你为什么要给它一个公共init属性(未定义)?

为什么init未定义?因为你没有返回任何东西 – 你正在运行一个函数并将init设置为函数的返回值,但是它没有返回任何东西,所以它将init设置为undefined.为什么要在那里初始化呢?

两种解决方案

function Foo () {
    this.change = function () { doStuff(); };
    var init = function () { this.change(); };
    // other stuff......
    init();
}

要么:

function Foo () {
    this.change = function () { doStuff(); };
    // other stuff....


    (function (context) {
       context.change();
       /* a bunch of other stuff that would be in init
          if there was no other stuff, why not just call this.change()? */
    }(this));
}

老实说,如果init是私有的,并且自动运行,那么创建真的需要公开吗?
你打算叫myObj.create();在它已经被创建之后?

为什么不这样做:

function Foo () {
    this.public1 = "Bob";
    this.public2 = 32;
    this.publicMethod = function () {};

    var create = function () { /* initialize here */ };
    create();
}

或者,如果你做的不仅仅是创造:

function Foo () {
    this.public1 = "Bob";
    this.public2 = 32;
    this.arrayOfThings = [];
    this.publicMethod = function () {};

    var create = function () {},
        overclock = function () {},
        polish = function () {};

    // Initialize Everything
    (function (context) {
        var thing;
        for (/* ... */) {
            thing = create();
            polish(thing);
            context.arrayOfThings.push(thing);
        }
        overclock(context.arrayOfThings); 
    }(this));
}

现在,您已将所有函数,属性和变量放在一个范围内,并且您已在另一个范围内进行初始化 – 所有设置逻辑都与最终对象的逻辑分开……和你可以做一些事情,比如根据输入参数分支你的对象(比如一个多态构造函数,它可以修改它给你的东西,根据它得到的东西,同时保持相同的界面)或者一个独立的工厂模式,其中所有的蓝图都是100%私人和封闭的),没有使实际的任务看起来像一堆乱七八糟的.

您不必在完成的对象之外调用设置(这意味着没有其他人可以调用已完成的对象上的设置,重新创建它/重置它).而且所有成本都是你要在this.init上使用的一个匿名函数.

点赞