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

OO javascript—构造函数中自执行函数的上下文/范围,javascript,Javascript,在构造函数中使用自动执行的anon函数时,我有一个关于上下文/范围的快速问题 遵守以下工作规范: function Foo() { this.height = 10; this.width = 10; this.init = function() { this.create(); }; this.create = function() { alert('test'); }; } var span1 = new F

在构造函数中使用自动执行的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。我希望构造函数中的init函数是自动执行的。这将为我提供如下代码:

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

var span1 = new Foo();
然而,在谷歌搜索了一段时间后,似乎使用了一个自动执行函数,这就给了它全局范围,因此这个.create在全局意义上是不存在的

我想我必须对call/apply做些什么,但我不确定具体是什么或在哪里

任何指点都将不胜感激

干杯,
Ad.

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

this.init = (function(ctx) {
    ctx.create();
})(this);
请注意,这是在声明
init
时执行的,因此除非在分配
init
之前分配
create
,否则它不会工作。在前面的示例中,这不是问题,因为
span1.init()
create
init
都已分配后手动调用。

它是如何工作的(请参见演示:):


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

我可能遗漏了什么,但也许你想要的是:

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
设置为
未定义
,因为您的函数不返回任何内容。

是,可以工作(只是有一个不同的参数,您根本不用):


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

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

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
问题,通过将
this
的值作为参数传递给内部作用域

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

function Foo () {
    this.change = function () { doStuff(); };
    this.init = (function (context) { context.change(); }(this));
}
那应该行得通。 ……然而

…你为什么要这样做? 与中一样,当您希望它自动构造时,为什么要给它一个
public
init
属性(它是
未定义的

为什么
init
未定义?因为您没有返回任何内容--您正在运行一个函数并将
init
设置为函数的返回值,但它没有返回任何内容,因此它将
init
设置为
未定义的
。那么,为什么有
init

两种解决方案:

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

老实说,如果
init
是私有的,并且自动运行,那么
create
真的需要公开吗? 是否要调用
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%私有和封闭的),而不是让实际的任务看起来像一堆假设和假设


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

为什么你需要一个自动执行的函数?只需离开所有函数,在构造函数范围内执行它。如果我理解正确,OP不希望调用
spa​n、 init();​Foo.prototype
设置为对象文本,因为这将覆盖
.prototype
上任何可能的现有属性。最好定义
.prototype.init
.prototype.create
individually@SperanskyDanil当你这样做的时候,你会在这一点上压碎整个原型链。如果在这个级别之前有任何原型属性连接到构造函数,那么它们都将被删除。想想
bob={name:“bob”}之间的区别;年龄=32岁
bob={name:“bob”};鲍勃={年龄:32}如果您以这样或那样的方式堆叠了原型实例,以尝试一种非平坦的继承模式,那么除了最后一站之外,您已经压碎了整个链。您所说的“不工作”是什么意思?您希望它能做什么?+1,尽管您的上一个示例仍然缺少正确的
this
valueHah。哎呀。对除了将上下文传递到最后一个函数之外,我认为这些函数足以完成任务。我要去修理
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));
}
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));
}