Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript避免了使用构造函数模式创建的对象对全局命名空间的污染_Javascript_Design Patterns_Namespaces - Fatal编程技术网

JavaScript避免了使用构造函数模式创建的对象对全局命名空间的污染

JavaScript避免了使用构造函数模式创建的对象对全局命名空间的污染,javascript,design-patterns,namespaces,Javascript,Design Patterns,Namespaces,为了创建JS库,我在内部使用构造函数模式创建对象。现在每种类型的对象都在它自己的文件中,所以说book在book.js中。所有文件都被连接起来,然后缩小 book.js -------- function Book (data) { this.data = data; } Book.prototype.rent = function(name) { console.log("Rent the book to " + name); } 现在,一旦加载了包含库的页面,我可以注意到,从浏

为了创建JS库,我在内部使用构造函数模式创建对象。现在每种类型的对象都在它自己的文件中,所以说book在book.js中。所有文件都被连接起来,然后缩小

book.js
--------

function Book (data) {
  this.data = data;
}

Book.prototype.rent = function(name) {
  console.log("Rent the book to " + name);
}
现在,一旦加载了包含库的页面,我可以注意到,从浏览器控制台可以直接创建图书对象

var b = new Book("somedata");
我在这里看到两个问题

  • 全局命名空间的污染,因为Book()对象现在在全局范围中可见
  • 安全问题,因为任何人都可以从控制台创建没有命名空间的对象

  • 该库实际上位于使用显示模块模式的命名空间下。我上面提到的问题是否可以安全处理?无论如何,要从全局名称空间(控制台)隐藏对象?

    您可以将它们包装在闭包中,以使它们远离全局名称空间,但是,这有一个根本问题,您希望您的函数/构造函数/什么都可以访问

    类似于在闭包中的文件中封装代码的方法,但会跟踪它们,以便在需要时可以访问它们。它用作访问和组织模块化代码的手段。我建议阅读browserify的文档,因为使用它可以解决这两个问题,尽管它会在您的最终用户身上实施模块系统(我认为这通常是一件好事,至少是一件值得做的事情,但是,这需要您根据具体情况来决定)


    我还应该指出,还有其他一些编写模块化代码的解决方案,比如or

    ,您可以在服务器端使用require模块并创建grunt任务来在入口点文件上运行browserify任务,这样所有代码都将转换为一个文件,并且不会从全局命名空间访问。查看更多信息

    安全问题,因为任何人都可以从控制台创建没有命名空间的对象

    这不是问题,任何人都可以从控制台在您的命名空间上创建对象

    由于
    Book()
    对象现在在全局范围中可见,因此全局命名空间受到污染。 该库实际上位于使用显示模块模式的命名空间下

    如果您将所有这些文件作为脚本加载,那么它们将把其中声明的类放在全局命名空间中。以某种方式使用全局名称空间是不可避免的,但是您可以使用显示模块模式将所有对象立即放在该自定义库名称空间上。您需要将这些文件包装在一个IEFE中,该IEFE将相应的类附加到
    City.Library

    City.Library.Book = (function() {
        function Book (data) {
            this.data = data;
        }
        Book.prototype.rent = function(name) {
            console.log("Rent the book to " + name);
        };
        return Book;
    }());
    

    或者,将文件视为模块(首选ES6),并让模块加载器/绑定器自动为您完成这项工作。

    代码中的显示模块模式在哪里?显示模块模式用于显示顶级命名空间对象(如“City.library”)的主库代码中。在这种情况下,可以根据需要创建/销毁上面提到的Book()等对象。但是,这些对象在全局名称空间中也是可用的,是的,如果您将所有这些文件作为脚本加载,那么它们将把这些类放在全局名称空间中。您需要将这些文件包装成模块模式(将相应的类附加到
    City.Library
    ),或者您需要将这些文件视为模块(首选ES6),并让模块加载程序/捆绑程序为您完成这项工作。@Bergi-我更愿意使用方法1将每个文件包装成模块模式。但是,我无法理解如何将类附加到City.Library.Just use
    City.Library.Book=(function(){…;return…;}())
    并确保它只在创建
    City.Library
    对象的主文件之后加载。正如我前面提到的,我目前正在使用gulp连接所有js文件并将其丑化。最后,我有一个library.min.js,它包含在HTML应用程序中。即使文件被连接并丑化,它们仍然在全局环境中可见。@sthustfo如果使用browserify,则不必使用连接,因为它将在解析所有模块依赖项时创建1个js文件。两个相关问题。+如果我需要在City.Library子模块中创建Book类型的对象,那么现在我必须调用
    new City.Library.Book()
    。有没有一种方法可以让我不必提及Book对象的完整名称空间?因为City.Library中的代码知道书的完整名称空间感觉很奇怪。这是正常的吗?第二个问题:+我读到使用构造函数模式(使用原型机制)的好处之一是库所需的总体内存减少,因为创建的所有对象的代码(文本部分,即函数定义)都是共享的,因此对象将更精简。使用此方法是否会消除优势或影响内存使用?请容忍我,如果我在大声思考?只是想弄清楚事情的意义。@sthustfo:取决于您所说的“在城市内。图书馆子模块”是什么意思。如果您在该对象的方法中,您可以使用
    this.Book
    。如果没有,您将希望在模块开头使用快捷方式
    var CL=City.Library
    ,以避免重复键入整个模块name@sthustfo:不,模块模式不会改变原型的工作方式。它们只是简化了代码的结构,并为您提供了一个额外的范围。您同样可以编写
    City.Library.Book=functionbook(data){…};City.Library.Book.prototype.rent=函数(名称){…}不带包装器