在构造函数中使用自执行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在全局意义上不存在。
我想我必须做一些电话/申请,但我不确定究竟是什么或在哪里。
非常感谢任何指针。
干杯, 广告。
答案 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)