javascript - 这种定义JS对象的方式有什么用途吗?

I'm maintaining some legacy code and I've noticed that the following pattern for defining objects is used:

var MyObject = {};

(function (root) {

    root.myFunction = function (foo) {
        //do something
    };

})(MyObject);

这有什么用途吗? 它只相当于做以下事情吗?

var MyObject = {

    myFunction : function (foo) {
        //do something
    };

};

I'm not about to embark in a holy quest to refactor the whole codebase to my likings, but I'd really like to understand the reason behind that roundabout way of defining objects.

谢谢!

6个解决方案
115 votes

It's called the module pattern http://toddmotto.com/mastering-the-module-pattern/

The main reason is for you to create truly private methods and variables. In your case, it's not meaningful because it's not hiding any implementation details.

Here's an example where it makes sense to use 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

如果您只使用直线物体,addervalue将公开

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
Juan Mendes answered 2019-08-29T03:40:15Z
22 votes

目的是限制闭包内函数的可访问性,以帮助防止其他脚本在其上执行代码。 通过将其包装在闭包中,您将重新定义闭包内所有代码的执行范围,并有效地创建私有范围。 有关详细信息,请参阅此文章:

[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
Jonathan Crowe answered 2019-08-29T03:41:01Z
6 votes

好处:

  1. 在私人范围内维护变量。

  2. 您可以扩展现有对象的功能。

  3. 性能提高了。

我认为上述三个简单点足以遵循这些规则。 并保持简单,除了编写内部功能。

Mateen answered 2019-08-29T03:41:49Z
6 votes

在您展示的特定情况下,在功能或可见性方面没有任何有意义的差异。

It's likely that the original coder adopted this approach as a sort of template allowing him to define private variables that could be used in the definition of things like myFunction:

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;   // <-- private variable
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

这避免了每次调用函数时计算root.myFunction = function,同时也防止它污染全局范围。

However, there's nothing essentially different from that and just saying

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);

Bottom line, there is no need to adopt this approach if you don't need to, but there is also no need to change it, since it works perfectly well and actually has some advantages.

answered 2019-08-29T03:45:46Z
6 votes
  1. 第一个模式可以用作获取对象并通过一些修改返回该对象的模块。 换句话说,您可以按如下方式定义此类模块。

    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
    

    并使用它像:

    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
    

    因此,该模块的可重用性可用于以后的使用。


  1. 在第一种模式中,您可以定义私有范围来存储私有属性,例如私有属性和方法。 例如,请考虑以下代码段:

    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
    

  1. 此模式可用于向所有类型的对象(如数组,对象文字,函数)添加方法或属性。

    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
    

在我看来,主要优势可能是第二个(创建私人范围)

Hi I'm Frogatto answered 2019-08-29T03:46:56Z
5 votes

此模式提供了一个范围,您可以在其中定义在全局范围中不可见的辅助函数:

(function (root) {

    function doFoo() { ... };

    root.myFunction = function (foo) {
        //do something
        doFoo();
        //do something else
    };

})(MyObject);

doFoo is local to the anonymous function, it can't be referenced from outside.

Barmar answered 2019-08-29T03:48:25Z
translate from https://stackoverflow.com:/questions/26788397/does-this-way-of-defining-js-objects-have-any-purpose