理解JavaScript函数、作用域和闭包

3

有人能详细解释一下这段js代码的作用吗?

(function (window) {
    var test = window['test'] = {};
    test.utils = new(function(){ ... })();
})(window);

我知道这个函数不是全局范围的。我知道它创建一个名为test的变量,该变量指向window对象中的一个空对象属性。我也知道utils是test的属性。
我不明白最后一部分的目的(window);或者为什么utils函数被指定为new。
请解释一下。

1
这是一个稍微误导的尝试,旨在使匿名(外部)函数中的代码免受对window的篡改。但这种做法是错误的,因为它并没有达到预期的效果 :-) 代码应该传递this而不是window - Pointy
2
new(function(){ ... })(); 只是定义构造函数并立即创建一个实例。这与 function Foo() {...}new Foo(); 相同。在这里使用对象字面量可能更容易,但我无法确定函数的内容。 - Felix Kling
可能是重复的问题:JS函数定义:最后一个括号的含义 - sdespont
这已经是我第二次看到有人使用IEFE,在传递(全局)window对象时添加属性。第一次是在某个JavaScript视频教程中,我想知道这是从哪里来的。 - Moritz Roessler
显示剩余2条评论
4个回答

2
它创建一个函数并立即调用该函数,传入window。该函数接收名为window的参数,然后在其上创建一个空对象,该对象既可以作为window上的属性test,也可以作为局部变量test。然后通过调用new生成一个对象,并将该对象分配给test.utils

我不理解最后一部分(window)的目的是什么;...

在您引用的代码中,它实际上没有任何作用,因为传递到主(外部)函数中的符号window与接收它的参数名称相同。如果它们的名称不同,则会有一个目的,例如:
(function(wnd) {
})(window);

这将使得window在函数中以wnd的形式被调用。

或者为什么utils函数被指定为new。

utils不会是一个函数(至少,除非你用...替换的代码做了一些非常奇怪的事情),它将成为通过调用该函数创建的对象。
整个内容可以更清晰地重写为:
(function(window) {

    var test;

    test = {};
    window['test'] = test;

    test.utils = new NiftyThing();

    function NiftyThing() {
    }

})(window);

这仍然是出于无聊的原因,做了那个 window 的事情,但希望这样就能更清楚地说明 new(function() { ... })(); 这一部分的作用。


如果您使用 window 变量,它可能有助于缩小文件体积。这是我听说的唯一原因,但我认为这些事情应该由压缩工具来完成 :-) - Bergi
那么 test.utils = new(function(){ ... })();test.utils = function(){ ... }; 之间有什么区别呢? - bflemi3
@bflemi3:在第一个例子中,test.utils将指向一个几乎肯定不是函数的对象。而在第二个例子中,test.utils将指向一个函数。 - T.J. Crowder

1

首先,这是一个自执行函数。

它通过将window对象作为函数输入参数来调用自身,以确保在整个函数内部,window具有预期的含义。

test.utils = new(function(){ ... })(); <--- This is an object constructor. 

当使用new运算符调用该函数时,它会变成一个对象构造器。
例如:
var conztructor = function() {
   this.name = "Matias";
};

var obj = new conztructor();
alert(obj.name); // <--- This will alert "Matias"!

(window); 的目的是创建一个新的变量和引用,保存 JavaScript Window 对象实例,避免其他库可能会重用 window(或任何其他)标识符,从而导致您自己的库出现问题。

这样做可以避免更改全局范围内由其他库使用的标识符。

更新

针对一些评论,运行此代码:

http://jsfiddle.net/wChh6/5/


你认为为什么window变量避免修改全局对象? - Bergi
^^^^^--- 它作为引用传递,修改将同时应用于全局对象,这就是我不理解背后目的的原因。 - Moritz Roessler
@Glutamat 请查看我的更新内容,现在我解释得比之前更好了 :) - Matías Fidemraizer
@Bergi 那是我第一次偶然发现的地方。MikeBoutin 在 JavaScript 的 聊天室 中发布了一个视频教程链接,这是视频,应该在8:30左右。 - Moritz Roessler
1
http://jsfiddle.net/wChh6/3/ -> 这并不会改变任何东西,你不能将window设置为null。而且我真的看不出来,将复制的引用设置为window对象的空值有什么意义。 - Moritz Roessler
显示剩余13条评论

0
当您使用最后一个括号定义函数时,该函数将在加载时自行执行,并使用给定的参数,在您的情况下是window
(function (window) {
    var test = window['test'] = {};
    test.utils = new(function(){ ... })();
})(window);

JS函数定义:最后一个括号的含义


0
这里发生的是声明一个新的匿名函数。最后一部分使用 (window) 调用该函数,并将 window 作为参数传递。
在函数内部,调用 test.utils = new(function(){ ... })(); 创建一个新对象(其内容由传递给 new 的函数定义),并将其赋值给 test.utils

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接