我维护了一些遗留代码,并且我注意到使用了以下用于定义对象的模式:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
这有什么用途吗?它只相当于做以下事情吗?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
我不打算采用神圣的方式将整个代码库重构为我的喜好,但我真的很想了解定义对象的迂回方式背后的原因。
谢谢!
答案 0 :(得分:115)
它被称为模块模式http://toddmotto.com/mastering-the-module-pattern/
主要原因是您要创建真正的私有方法和变量。在您的情况下,它没有意义,因为它没有隐藏任何实现细节。
这是一个使用模块模式的例子。
var MyNameSpace = {};
(function(ns){
// The value variable is hidden from the outside world
var value = 0;
// So is this function
function adder(num) {
return num + 1;
}
ns.getNext = function () {
return value = adder(value);
}
})(MyNameSpace);
var id = MyNameSpace.getNext(); // 1
var otherId = MyNameSpace.getNext(); // 2
var otherId = MyNameSpace.getNext(); // 3
如果您只是使用直接对象,adder
和value
将成为公开
var MyNameSpace = {
value: 0,
adder: function(num) {
return num + 1;
},
getNext: function() {
return this.value = this.adder(this.value);
}
}
你可以通过做
这样的事情来打破它MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function
但是使用模块版本
MyNameSpace.getNext(); // 1
// Is not affecting the internal value, it's creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3
答案 1 :(得分:22)
目的是限制闭包中的辅助功能,以帮助阻止其他脚本在其上执行代码。通过将其包裹在闭包周围,您将重新定义闭包内所有代码的范围,并有效地创建私有范围。有关详细信息,请参阅此文章:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
来自文章:
JavaScript中最着名的问题之一是它依赖于a 全局范围,这基本上意味着您声明的任何变量 功能之外的同名空间:不祥之物 窗口对象。由于网页的性质,许多脚本来自 不同的来源可以(并将会)在共享的同一页面上运行 共同的全球范围,这可能是一个非常糟糕的事情 可以导致名称冲突(具有相同名称的变量) 覆盖)和安全问题。为了尽量减少我们可以使用的问题 JavaScript强大的闭包创建私有范围我们可以 确保我们的变量对页面上的其他脚本不可见。
<强>代码:强>
var MyObject = {};
(function (root) {
function myPrivateFunction() {
return "I can only be called from within the closure";
}
root.myFunction = function (foo) {
//do something
};
myPrivateFunction(); // returns "I can only be called from within the closure"
})(MyObject);
myPrivateFunction(); // throws error - undefined is not a function
答案 2 :(得分:6)
在您展示的特定情况下,在功能或可见性方面没有任何有意义的差异。
原始编码人员可能采用这种方法作为一种模板,允许他定义可用于myFunction
之类定义的私有变量:
var MyObject = {};
(function(root) {
var seconds_per_day = 24 * 60 * 60; // <-- private variable
root.myFunction = function(foo) {
return seconds_per_day;
};
})(MyObject);
这避免了每次调用函数时计算seconds_per_day
,同时也不会污染全局范围。
但是,没有什么本质上不同,只是说
var MyObject = function() {
var seconds_per_day = 24 * 60 * 60;
return {
myFunction: function(foo) {
return seconds_per_day;
}
};
}();
原始编码器可能更喜欢能够使用root.myFunction = function
的声明性语法向对象添加函数,而不是myFunction: function
的对象/属性语法。但这种差异主要取决于偏好。
然而,原始编码器采用的结构具有以下优点:可以在代码中的其他位置轻松添加属性/方法:
var MyObject = {};
(function(root) {
var seconds_per_day = 24 * 60 * 60;
root.myFunction = function(foo) {
return seconds_per_day;
};
})(MyObject);
(function(root) {
var another_private_variable = Math.pi;
root.myFunction2 = function(bar) { };
})(MyObject);
总而言之,如果您不需要采用这种方法,则无需采用这种方法,但也不需要对其进行更改,因为它运行良好并且实际上具有一些优势。
答案 3 :(得分:6)
第一个模式可以用作获取对象并通过一些修改返回该对象的模块。换句话说,您可以按如下方式定义此类模块。
var module = function (root) {
root.myFunction = function (foo) {
//do something
};
}
并使用它:
var obj = {};
module(obj);
因此,该模块的可重用性可用于以后的使用。
在第一种模式中,您可以定义私有范围来存储您的私有资源,例如私有属性和方法。例如,请考虑以下代码段:
(function (root) {
// A private property
var factor = 3;
root.multiply = function (foo) {
return foo * factor;
};
})(MyObject);
此模式可用于向所有类型的对象添加方法或属性,例如数组,对象文字,函数。
function sum(a, b) {
return a + b;
}
(function (root) {
// A private property
var factor = 3;
root.multiply = function (foo) {
return foo * factor;
};
})(sum);
console.log(sum(1, 2)); // 3
console.log(sum.multiply(4)); // 12
在我看来,主要优势可能是第二个(创建私人范围)
答案 4 :(得分:6)
的优点:
将变量维护在私有范围内。
您可以扩展现有对象的功能。
性能提升。
我认为上述三个简单点足以遵循这些规则。并保持简单,除了编写内部功能。
答案 5 :(得分:5)
此模式提供了一个范围,您可以在其中定义在全局范围内不可见的辅助函数:
(function (root) {
function doFoo() { ... };
root.myFunction = function (foo) {
//do something
doFoo();
//do something else
};
})(MyObject);
doFoo
是匿名函数的本地函数,不能从外部引用。