前言
记得long long ago,刚刚开始写JS的时候,我喜欢写一些函数在JS文件里边,然后通过script标签引进来,在DOM节点上绑定onclick等事件,看了很多人写的代码,也大多是这样。
后来会发现,当项目小的时候这么做为了快速开发是可以接受的,然而当很多人一起开发一个Javascript大应用的时候,你会发现不同的代码风格跟全局变量会导致很多冲突,这是一个很痛苦的事情。
曾经的经历
用过jQuery的人就知道其主要的变量符号就是$,没错!因此很多项目的开发人员也要学,就自己把$定义成别的含义了,我心里对其是无敌的鄙视跟厌恶。
我曾经拿过一个项目使用jQuery的,然后上头要我使用一个已有的富文本编辑器,这样就有两个JS文件了
jquery.js和editor.js,于是我要开始写该页面的逻辑了,我发现editor.js里边自定义了$符号,我原本想要把它直接替换成别的标志符,但是悲剧的是,它还有一些插件也会用到,混乱的结构导致我花了很多时间去解决这个冲突。
全局Window
我们都知道,在文件中直接定义的变量跟函数(不嵌套在任何域底下的)都是属于全局的,也就是都在当前页面的window变量底下。例如:
function test1(){
}
var name;
function test2(){
i = 1;
}
上边代码中的name,test1,test2和i都是属于window底下的全局变量,也就是可以通过以下三种办法访问到它们:
1.直接访问name,test1()等;
2.使用window["name"], window['test1']()等;
3.使用window.name,window.test1()等。
注意:上边代码中的i虽然是在test2函数里边才出现的,因为其前面没有使用var关键字,解释器会认为它在test2的上一层定义的,依次查找上一层,直到找到window全局,如果发现还是未定义,那么将其挂在window底下成为了全局变量。
所以你直接定义的函数通通都挂到了window底下,这就是一种污染了,当很多人定义各种变量跟函数,你又得同时引入进来的时候,这个冲突的概率就变大了。
减少污染
那为了避免过多这样的冲突,以及模块之间的耦合性更低,需要减少这样的污染。
此时我们会想,那不要把变量定义在全局呗,采用类似C++的命名空间,Java的包的思路就行啦。
首先就是将不同的模块划入到不同的全局“包”(这里的包的概念实际上就是一个Javascript对象而已)。
例如,程序员A为全局添加一个A变量,然后他把自己定义的函数/变量全部挂到A底下,这样就跟程序员B所定义的隔离了。
再者我们可以使用函数域来隔离一些局部变量的冲突,比如说程序员A写的代码如下:
(function(obj){
/* 在这里边就与外边隔离了,定义的局部变量不会与外界干扰 */
/* 为了跟外界达到共享的目的,还可以为其加入参数,例如obj,在最后调用的时候把相关的参数传进来,例如下边的window */
var A = {};//定义一个A包
var tmp;//临时变量
A.i = 1;//定义这个包里边的i变量
A.func = function(){alert('I am A');};
obj.A = A;/* 把A包挂到obj底下 */
})(window);
当离开了这个函数域之后,tmp等局部变量被销毁(只要不要存在在闭包里边),程序员A定义的东西通通挂到了变量window.A底下,从而减少了很多污染,避免了不必要的冲突。
回到过去
再次回到刚刚提过的那个经历,如果我现在为editor.js整个包围在function里边,通过这种方式把$给隐藏在一个包里边,在它的其他控件中也采取这样的做法,当然还要做一小点改动:
/* editor.js */
(function(obj){
/* 原先editor里边的内容 */
/* 里边有定义了自己的$标志 */
obj.editor = obj.editor || {};//如果没有editor对象,则生成一个空对象
obj.editor.$ = $;//把$挂在全局的editor对象上
})(window);
/* 其他控件.js */
(function(obj){
var $ = obj.$;//把$恢复
/* 原先控件的内容 */
})(window.editor);
当然咯,如果editor.js有些功能需要暴露到全局的话,还需要将其进一步的挂在editor变量底下,这里只是一个示范。
本篇总结
很多框架都采用了这种做法减少全局污染,可能很多人一开始对这种做法有疑惑,这里只是个人理解拿出来分享一下,继续欢迎交流。
分享到:
相关推荐
- **作用域冲突**:全局变量可能会导致命名冲突,尤其是在大型项目中,多个模块可能无意间使用相同的全局变量名称,从而引发错误。 - **内存消耗**:全局变量在整个程序生命周期内都存在,会占用内存资源,因此不...
它能够帮助开发者创建一个局部作用域,从而保护内部变量不受外部环境的影响,同时也不会污染全局命名空间。 ##### 不推荐的做法 直接在全局作用域中定义变量: ```javascript var x = 10, y = 100; console.log...
2. **减少全局变量**:通过使用局部变量,我们可以避免污染全局作用域,减少因全局变量过多带来的问题。 3. **封装和模块化**:自执行函数可以视为一个小型的模块,封装了其内部逻辑,使得代码更加模块化,便于组织...
这两个模块都是立即执行的函数表达式(IIFE),用于创建私有作用域,避免污染全局空间。每个模块内部又定义了一些方法,如`isArray`、`inArray`、`trim`、`ltrim`和`rtrim`,这些方法分别用于检测数组、查找数组中的...
**理由**:如果省略了`var`关键字,则变量会默认成为全局变量,这可能导致变量名冲突。此外,不使用`var`声明的变量其作用域难以确定,容易无意间泄漏到全局作用域中,从而引发各种问题。因此,为了确保变量的作用域...
在ES6引入了`let`和`const`后,可以更方便地管理变量的作用域,`let`在块级作用域内有效,而`const`用于声明不可变的常量,它们都不会污染全局命名空间。 4. 利用闭包(Closures)创建私有变量。通过函数返回一个...
同时,避免在函数内部使用全局变量,除非确实必要,以减少命名冲突和内存泄漏的风险。 此外,合理利用作用域可以提高代码效率。例如,使用块级作用域(如`let`)来限制变量的作用范围,避免变量污染。函数参数应...
了解作用域有助于防止变量污染,即全局变量过多导致的命名冲突。此外,JavaScript还引入了闭包,这是一种特殊的作用域现象,允许函数访问并操作其词法作用域内的变量,即使该函数在其外部被调用。闭包在实现数据封装...
5. **避免全局变量和作用域污染**:全局变量会增加内存消耗,并可能导致命名冲突。使用立即执行函数表达式(IIFE)或模块系统,确保变量的作用域限制在最小范围内。 6. **合理使用闭包**:虽然闭包在JavaScript中很...
2. **减少全局污染**:使用伪命名空间的方式,可以将相关的函数和数据组织在一起,避免了全局变量的过多使用,减少了命名冲突的风险。 3. **易于维护和扩展**:每个模块都有清晰的边界,便于理解和维护。同时,如果...
- **命名空间** 使用命名空间可以组织代码,避免污染全局命名空间。通常通过对象来实现,如`MyApp.module.function()`。 遵循这些规范,不仅可以提高代码质量,还能使团队之间的合作更加顺畅,降低维护成本。良好...
正确使用‘var’声明局部变量,可以避免变量污染全局命名空间,防止出现意料之外的错误。 2. 特性检测而非浏览器检测:依赖于浏览器的特性而非版本来决定执行的代码,可以更加精确地为不同浏览器提供合适的代码。...
但创建过多的全局变量可能导致命名冲突,因此通常应避免。 2. **局部作用域**: 在函数内部声明的变量是局部变量,只能在该函数内部访问。一旦函数执行完毕,局部变量通常会被销毁。 JavaScript还有一个特殊的**...
- **样式隔离**:每个组件的样式都是独立的,避免了全局样式的污染。 3. **使用goober编写样式** 在goober中,你可以使用`styled`函数创建样式组件,然后像使用React组件一样使用它们。例如: ```jsx const ...
然而,全局作用域的使用需要注意避免污染全局命名空间,因为过多的全局变量可能导致命名冲突,影响代码的可维护性和性能。 2. 函数作用域:函数作用域指的是在函数内部声明的变量只能在该函数内部访问。这种作用域...
2. **立即执行函数表达式(IIFE)**:用 `(function() { /* code */ })()` 包裹代码,确保函数不会污染全局作用域。 3. **模板字符串**:使用反引号(``)创建字符串,可以方便地插入变量和表达式,如 `${var}`。 4....
- 利用块级作用域,如 `let` 和 `const`,避免变量污染全局空间。 - 使用严格相等运算符 `===` 和 `!==`,避免类型转换带来的问题。 - 避免使用容易引起混淆的加法和减法操作,例如 `++` 和 `--`。 - 避免使用 `...