作者:阡蓝fliona | 来源:互联网 | 2023-10-12 17:13
[路飞]每日一答:如何利用闭包和立即执行函数实现类库的封装?-highlight:ascetictheme:channing-cyan如何利用闭包和立即执行函数实现类库的封装
highlight: ascetic
theme: channing-cyan
如何利用闭包和立即执行函数实现类库的封装
封装类库的特点
类库是我们在开发中经常用到的,但是在使用的时候我们很少会考虑他是如何设计的,如何实现封装的。
首先我们要了解类库的特点是什么。类库最基础的要求就是高复用性和低耦合性。这就引申出类库实际上不仅要求脱离业务更要求他有自己的作用域和命名空间。那么利用闭包和立即执行函数就可以做到这一点。
比较一下
第一种写法:
var name = 'defaultName' // 变量 name
function Person () {
this.name = name // 属性 name 默认为变量 name
}
const p = new Person()
console.log(p) // Person {name: "detaultName"}
这么写功能上固然是没有问题的,我们可以看到返回了一个默认值为 defaultName
的 person
对象
。但是,如果你尝试去打印 this.name
或者 window.name
:
console.log(this.name) // defaultName
console.log(window.name) // defaultName
不难发现,我们全局作用域下的 name
属性也受到了影响。
第二种写法
const Person = (function () {
var name = 'defaultName' // 变量 name
const Person = function () {
this.name = name // 属性 name 默认为变量 name
}
return Person
})()
const p = new Person()
console.log(p) // Person {name: "detaultName"}
console.log(this.name) // ''
console.log(window.name) // ''
采用了闭包和立即执行函数的形式,为类库的实现创建了单独的作用空间,最终返回一个对象或一个方法的形式。这样一来,类库下的作用域以及变量就不会对全局造成影响,也不会受到命名的限制。
典型案例
大名鼎鼎 jQuery 架构:
;(function(global, factory) {
factory(global);
}(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {};
// 核心方法
// 回调系统
// 异步队列
// 数据缓存
// 队列操作
// 选择器引
// 属性操作
// 节点遍历
// 文档处理
// 样式操作
// 属性操作
// 事件体系
// AJAX交互
// 动画引擎
return jQuery;
}));
尝试去分解一下。首先是一个自执行函数:
function(global, factory) { factory(global); }
它包含了两个入参,第一个是挂载对象(默认全局),第二个是工厂方法。那么这个自执行对象的传参分别是
typeof window !== "undefined" ? window : this
以及下面的整段方法了
function(window, noGlobal) {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {};
// 核心方法
// 回调系统
// 异步队列
// 数据缓存
// 队列操作
// 选择器引
// 属性操作
// 节点遍历
// 文档处理
// 样式操作
// 属性操作
// 事件体系
// AJAX交互
// 动画引擎
return jQuery;
}
如果我们不使用立即执行函数去实现就应该会变成这样:
var window = typeof window !== "undefined" ? window : this
function(window) {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {};
// 核心方法
// 回调系统
// 异步队列
// 数据缓存
// 队列操作
// 选择器引
// 属性操作
// 节点遍历
// 文档处理
// 样式操作
// 属性操作
// 事件体系
// AJAX交互
// 动画引擎
return jQuery;
}
由于自身的入参本身就是全局对象window,这种写法可能也不会对全局造成什么影响,但是也太不优雅了。