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

时间:2012-08-21 12:53:39

标签: 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在全局意义上不存在。

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

非常感谢任何指针。

干杯, 广告。

5 个答案:

答案 0 :(得分:2)

Adi,您在示例中所做的事情有两个问题。 第一个问题是在立即调用的函数内部this === window

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

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

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

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

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问题,也可以将this的值作为参数传递给内部范围......

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

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

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

...你为什么这么做呢? 如果你希望它自动构建,你为什么要给它一个public init属性(undefined)?

为什么init undefined?因为你没有返回任何内容 - 你正在运行一个函数并将init设置为函数的返回值,但它没有返回任何内容,所以它将init设置为undefined 。为什么那里有init呢?

两种解决方案:

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是私有的,并且是自动运行的,那么create是否真的需要公开? 你打算在myObj.create();创建之后打电话给你吗?

为什么不这样做:

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

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

或者,如果你做的不仅仅是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上使用的一个匿名函数。

答案 1 :(得分:0)

您可以将上下文传递给新的闭包:

this.init = (function(ctx) {
    ctx.create();
})(this);

请注意,这是在声明init时执行的,因此除非您在指定create之前指定init ,否则它将无效。在您之前的示例中,这不是问题,因为在span1.init()create分配后,init会被手动调用。

答案 2 :(得分:0)

它是如何工作的(参见演示:http://jsfiddle.net/Jw8jz/1/):

function Foo() {
  this.height = 10;
  this.width = 10;

  this.init();
}

Foo.prototype = {
  init: function() {
    this.create();
  },

  create: function() {
    alert('test');
  }
};

var span = new Foo();

了解有关原型属性的更多信息!

答案 3 :(得分:0)

我可能会遗漏一些东西,但也许你想要的是:

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

    this.init();
} 

当然,类似地,您可以完全删除init功能,或将其设为私有。例如:

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

    this.create();
} 

此外,请注意this.init = (function() {})();this.init设置为undefined,因为您的函数不返回任何内容。

答案 4 :(得分:0)

是的,call将起作用(apply只有一个不同的参数参数,你完全不使用它):

this.init = (function() {
    this.create();
    // return something?
}).call(this);