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

Seb*_*ste 87 javascript javascript-objects

我正在维护一些遗留代码,我注意到使用了以下用于定义对象的模式:

var MyObject = {};

(function (root) {

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

})(MyObject);
Run Code Online (Sandbox Code Playgroud)

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

var MyObject = {

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

};
Run Code Online (Sandbox Code Playgroud)

我不打算采用神圣的方式将整个代码库重构为我的喜好,但我真的很想了解定义对象的迂回方式背后的原因.

谢谢!

Jua*_*des 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
Run Code Online (Sandbox Code Playgroud)

如果你只使用一个直的物体,adder并将value公开

var MyNameSpace = {
    value: 0,
    adder: function(num) {
       return num + 1;
    },
    getNext: function() {
       return this.value = this.adder(this.value);
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以通过做类似的事情来打破它

MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function
Run Code Online (Sandbox Code Playgroud)

但随着模块版本

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
Run Code Online (Sandbox Code Playgroud)

  • @torazaburo OP的例子不是一个很好的例子,我提供了一个真实的例子来说明何时使用模块模式. (20认同)
  • 这并没有真正回答两种选择之间存在差异的问题? (2认同)
  • @punund JS没有编译器,它有解释器`:)` (2认同)

Jon*_*owe 22

目的是限制闭包内函数的可访问性,以帮助防止其他脚本在其上执行代码.通过它包裹一个关闭你正在重新定义范围内执行的,内部的所有代码封闭,并有效地创建一个私人范围.有关详细信息,请参阅此文章:

http://lupomontero.com/using-javascript-closures-to-create-private-scopes/

来自文章:

JavaScript中最着名的问题之一是它依赖于全局范围,这基本上意味着您在函数外部声明的任何变量都存在于同一名称空间中:不祥的窗口对象.由于网页的性质,来自不同来源的许多脚本可以(并且将会)在共享全局范围的同一页面上运行,这可能是非常糟糕的事情,因为它可能导致名称冲突(具有相同名称的变量)被覆盖)和安全问题.为了最大限度地减少这个问题,我们可以使用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
Run Code Online (Sandbox Code Playgroud)


小智 6

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

原始编码器很可能采用这种方法作为一种模板,允许他定义可用于定义事物的私有变量myFunction:

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

这避免了seconds_per_day每次调用函数时的计算,同时也防止它污染全局范围.

然而,没有什么本质上不同,只是说

var MyObject = function() {
    var seconds_per_day = 24 * 60 * 60;
    return {
        myFunction: function(foo) {
            return seconds_per_day;
        }
    };
}();
Run Code Online (Sandbox Code Playgroud)

原始编码器可能更喜欢能够使用声明性语法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);
Run Code Online (Sandbox Code Playgroud)

最重要的是,如果你不需要,就没有必要采用这种方法,但也没有必要改变它,因为它工作得非常好并且实际上有一些优点.


fro*_*tto 6

  1. 第一个模式可以用作获取对象并通过一些修改返回该对象的模块.换句话说,您可以按如下方式定义此类模块.

    var module = function (root) {
        root.myFunction = function (foo) {
            //do something
        };
    }
    
    Run Code Online (Sandbox Code Playgroud)

    并使用它像:

    var obj = {};
    module(obj);
    
    Run Code Online (Sandbox Code Playgroud)

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


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

    (function (root) {
    
        // A private property
        var factor = 3;
    
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(MyObject);
    
    Run Code Online (Sandbox Code Playgroud)

  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
    
    Run Code Online (Sandbox Code Playgroud)

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


Mat*_*een 6

好处:

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

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

  3. 性能提高了.

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


Bar*_*mar 5

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

(function (root) {

    function doFoo() { ... };

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

})(MyObject);
Run Code Online (Sandbox Code Playgroud)

doFoo 是匿名函数的本地函数,它不能从外部引用.