正在封装外部jQuery脚本

Enclosing external jQuery script

本文关键字:jQuery 脚本 外部 封装      更新时间:2023-09-26

我有一个外部JavaScript文件,它将用于包含许多其他脚本的页面。我的脚本包含了大量侦听事件的jQuery,并且在设计中,我声明了许多全局var。我一直在阅读最佳实践文章,其中有很多关于"污染全局命名空间"和无意中的脚本交互的内容。

封装JavaScript文件的最佳方式是什么

  • 我仍然可以访问外壳外的变量
  • jQuery事件侦听器将功能正常

我不能随意透露代码,所以即使是一般的回复也很感激。此外,欢迎提供任何其他提示,使脚本不易受到页面上其他脚本的攻击。

我发现了常规JavaScript的外壳样式,但是jQuery的使用会使其复杂化吗?

一般来说,这归结为将对象封装到一个"命名空间"中。我在这里使用引号是因为这个术语不是JavaScript中的官方语义,而是通过基本对象封装实现的。

有几种方法可以做到这一点,最终取决于个人偏好。

一种方法是只使用一个基本的JS对象,并将所有内容都保留在其中。对象的名称应该是语义的,并赋予对象一些意义,但除此之外,它的目的只是包装您自己的代码,并将其排除在全局名称空间之外。

var SomeName = {
    alpha: 1,
    beta: {a: 1, b: 2},
    gamma: function(){ 
        SomeName.alpha += 1;
    }
}

在这种情况下,全局命名空间中只有SomeName。这种方法的一个缺点是,命名空间内的所有内容都是公共的,您必须使用完整的命名空间来引用对象,而不是使用"this"-例如,在SomeName.gamma中,我们必须使用SomeName.alpha来引用alpha的内容。

另一种方法是使命名空间成为具有属性的函数。这种方法的一个好特性是可以通过闭包创建"private"变量。它还允许您在没有完全命名空间引用的情况下访问封闭函数和变量。

var SomeName = (function(){
   var self = this;
   var privateVar = 1;
   var privateFunc = function() { };   
   this.publicVar = 2;
   this.publicFunc = function(){
       console.log(privateVar);
       console.log(this.publicVar); // if called via SomeName.publicFunc
       setTimeout(function(){ 
           console.log(self.publicVar);
           console.log(privateVar);
       }, 1000);
   };
}();

这种方法的另一个好处是,它可以保护希望使用的全局变量。例如,如果您使用jQuery,并使用另一个创建$变量的库,您可以通过以下方法确保在使用$时引用jQuery:

var SomeName = (function($){
    console.log($('div'));
})(jQuery);

一种方法是这样命名名称空间:

var MyNamespace = {
    doSomething: function() {},
    reactToEvent: function() {},
    counter: 0
}

您只需要使用名称空间MyNamespace.reactToEvent来引用函数或变量。这可以很好地分离window(所有对抗都在那里)中通常会有的内容。

您可以将代码封装在一个匿名的Javascript函数中,只返回您想向外界公开的内容。您需要将var作为全局变量的前缀,以便它们只保留在匿名函数的作用域中。类似这样的东西:

var myStuff = (function() {
   var globalVar1;
   var globalVar2;
   var privateVar1;
   function myFunction() {
     ...
   }
   function myPrivateFunction() {
     ...
   }
   return {
      var1: globalVar1,
      var2: globalVar2,
      myFunction: myFunction
   };
})();

现在您可以访问myStuff.var1myStuff.myFunction()

封装或限制命名空间污染的两种方法

1) 创建一个全局var,并将您需要的一切都放入其中。

var g = {};
g.somevar = "val";
g.someothervar = "val2";
g.method1 = function() 
{
   // muck with somevar
   g.somevar = "something else";
};

2) 对于内联脚本,请考虑限制调用的函数的范围。

<script>
(  
   function(window)
   {
      // do stuff with g.somevar
      if(g.somevar=="secret base")
        g.docrazystuff();      
   }
)();  // call function(window) then allow function(window) to be GC'd as it's out of scope now
</script>

我刚开始使用RequireJS,现在已经痴迷于它了。

它基本上是一个模块化JavaScript格式的依赖关系管理系统。通过这样做,您实际上可以消除将任何内容附加到全局命名空间的情况。

好的是,您只引用页面require.js上的一个脚本,然后告诉它先运行哪个脚本。从那里开始,一切都变得神奇。。。

下面是一个示例实现脚本:

require([
   //dependencies
   'lib/jquery-1.6.1'
], function($) {
   //You'll get access to jQuery locally rather than globally via $

});

阅读RequireJS API,看看这是否适合您。我现在所有的剧本都是这样写的。这很好,因为在每个脚本的顶部,您都可以确切地知道与服务器端语言(Java或C#)相似的依赖项。

这是jQuery插件的常见做法,原因与您提到的相同:

;(function ($) {
    /* ... your code comes here ... */
})(jQuery);

这是一个直接的功能。如果您在里面声明您的"全局"变量,它们将是这个闭包的本地变量(对于您在里面创建的代码来说仍然是"全局"的)。您的事件监听器也将在这里工作,您仍然能够访问真实的全局变量。