前端多人协作 - 全局变量污染问题(匿名IIFE / ES6块级作用域)

前言

大型前端项目开发中,每位开发者可以定义与保存所有应用资源的全局变量,如果定义过多的全局变量很有可能造成全局变量的冲突,也就是全局变量的污染问题。全局变量过多不仅会造成命名冲突,而且还会削弱程序灵活性,增加各模块之间的耦合性,将来模块之间的合并拼接将非常困难。
前端多人协作 - 全局变量污染问题(匿名IIFE / ES6块级作用域)_第1张图片
如上图所示,全局对象只有一个,当各模块进行耦合时 程序员A程序员C 发生了冲突,程序员B程序员C 又发生了冲突,可以看到,全局变量污染将是一个大型项目的噩梦,各模块之间修改调试非常影响开发效率,显然不聪明。为了避免过多这样的冲突,以及模块之间的耦合性更低,必须减少或隔绝这样的污染。

我觉得在小型前端项目中,为了增加开发效率是绝对可以不理会全局变量污染问题。

污染JQuery全局变量(JQuery/$)

// ____假设已引入 JQuery 与所需 DOM 元素____
// 尝试访问 $
console.log(window.$) //ƒ(e,t){return new w.fn.init(e,t)}
// 尝试污染 $
var $ = `contaminated[污染成功]`
console.log(window.$) //contaminated[污染成功]
// 尝试使用 $
$('#demo').click(function (){
  window.alert(`污染失败!`)//$ is not a function
})

首次访问 window.$ 时, 一切平静,当用 $ 命名并重新赋值挂载到 window 中时,可以看到打印结果已经变成了我所定义的字符串 “contaminated[污染成功]” ,最后使用 JQuery 正常提供的 $ 选取 DOM节点时,发生了 “$ is not a function” 不存在的错误。

原本正常运行的 JQuery 代码,却被一个全局变量污染造成 “全身瘫痪” ,可见全局变量污染多么恐怖。

通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名空间。这点非常是一个JS框架必须支持的功能,jQuery被应用在成千上万的JavaScript程序中,必须确保jQuery创建的变量不能和导入他的程序所使用的变量发生冲突。

匿名IIFE

在文件中直接定义的变量与函数(不嵌套在任何域底下的)都是属于全局,也就是都在当前页面顶级对象 window 下。根据 前言 中赘述的问题,我们是否可以利用 匿名IIFE 来隔绝每位程序员的全局变量?怎么隔绝?会不会影响什么?

如果每位程序员自己定义一个对象通过属性来存放自己的变量,然后把该对象挂载到 window 中,最后通过 . 访问其属性与方法。 这样做既隔绝了变量污染,又达到了共享目的,如图:
前端多人协作 - 全局变量污染问题(匿名IIFE / ES6块级作用域)_第2张图片
如上图所示,把思维转换为代码:

// 匿名IIFE(实现隔离与共享)
(function(obj){  
  // 这里就像ES6块级作用域一样/定义的局部变量不会与外界变量干扰互斥(++ 隔离 ++)
  // 这里同样允许传参/如Package_A/最后调用的时候把相关参数传进来/如window(++ 共享 ++)

  // 定义每位开发者 "专属" 对象包
  var Package_A = {};//定义一个A包   
  
  // 把值与方法挂载到该对象包
  Package_A.msg = `msg`;
  Package_A.Show = function (){
    console.log(`Show方法`)
  };
  
  // 把对象包(Package_A)挂载到 window 下
  obj.Package_A = Package_A;
      
})(window);

// 尝试访问自定义包 Package_A
console.log(window.Package_A)//{msg: "msg", Show: ƒ}

// 尝试污染 msg (污染失败)
var msg = new Error()
console.log(window.msg)//Error
console.log(window.Package_A.msg)//msg

// 尝试访问自定义包 Package_A 属性与方法(共享成功)
console.log(window.Package_A.Show())//Show方法
console.log(window.Package_A.msg)//msg

这样,程序员A 通过匿名IIFE自定义一个对象包,把所有变量及方法都挂载到这个对象包中,然而 程序员B / 程序员C 也有自己的对象包,只要每位开发者的对象包命名不冲突,就不会存在全局变量污染问题。

ES6块级作用域

匿名IIFE 目的在于建立一个块级作用域,让一些变量出了这个作用域就立马销毁,从而达到变量不被污染。现在有了 ES6 块级作用域概念,使用 匿名IIFE 不再是唯一选择了,因为 ES6 块级作用域能更简洁的解决全局变量污染问题。
前端多人协作 - 全局变量污染问题(匿名IIFE / ES6块级作用域)_第3张图片

引用阮一峰老师一语:块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。

不再使用 匿名IIFE 模拟块级作用域概念,而是使用真正的块级作用域:

// 【块级作用域】
// 定义每位开发者 "专属" 对象包
let Package_A = {

  // 把值与方法挂载到该对象包
  msg: `msg`,
  Show: function (){
    console.log(`Show方法`)
  }
}

// 尝试访问自定义包 Package_A
console.log(Package_A)//{msg: "msg", Show: ƒ}

// 查看 Package_A 是否挂载在 window
console.log(window.Package_A)//undefined

// 尝试污染 msg (污染失败)
let msg = new Error()
console.log(msg)//Error
console.log(Package_A.msg)//msg

// 尝试访问自定义包 Package_A 属性与方法(共享成功)
console.log(Package_A.Show())//Show方法
console.log(Package_A.msg)//msg

同样,利用块级作用域概念,每位开发者维护各自独立的区域,这种块级作用域写法要优于 匿名IIFE 。这是理所当然的,因为 匿名IIFE 就是为了模拟块级作用域,我们应当积极使用块级作用域这种概念,而少用 匿名IIFE 来模拟块级作用域。

{
…end
}

你可能感兴趣的:(前端多人协作/数据结构算法)