-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Day12 - 如何利用闭包完成类库封装 #56
Comments
类库封装最重要的要求就是不能让类库中的变量污染全局,而这正是闭包的精髓特征。通过即时函数将类库封装在即时函数func中,这样保证了所有的变量在一个独立的空间内,不会污染全局环境,也不会被其他的对象改变内部环境结构。 |
首先我们要强调一下我们在封装类库的时候为什么要用到闭包和立即执行函数。类库的主要的几个特点就是复用性高,耦合性低。低耦合性就要求类库不仅脱离业务,最好是有自己单独的作用域和变量名。假设类库中使用 var 定义了一个name 的变量,那么他就很可能会影响到 window下的name。但如果采用立即之心函数和闭包就能够为类库创建单独的作用域,从而避免影响全局,在变量的命名上面也将不会收到外部作用域的影响。在ES6之前是没有class这个概念的,但是通过闭包可以起到类似 Class 的作用, |
jQuery就是一个工具类库,它就利用了闭包的思想,保护了它自己私有化的特点,不给全局变量造成污染。 (function(global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") {
// 当前运行JS的环境是支持CommonJS模块规范「node.js/webpack,浏览器默认不支持」
// webpack环境下
// module.exports = factory(window, true)
// node 环境下 【不支持jQuery的使用】
// module.exports = function(w) {...}
// 使用 let $ = require('jquery'); -> $() ->报错了
module.exports = global.document ?
factory(global, true) :
function (w) {
if(!w.document) {
throw new Error("jQuery requires a window with a document")
}
return factory(w)
}
} else {
// 浏览器或者webview环境
// -> B(window)
factory(global);
}
})(typeof window !== 'undefined' ? window : this, function (window, noGlobal) {
"use strict";
// 浏览器环境下导入JQ: window -> window noGlobal -> undefined
// webpack环境下运行:window-> window noGlobal -> true 把factory执行的返回值导出
}) 在自己封装类库时,也要进行参照jquery思想进行判断是否支持对应的规范 |
|
var Parent = (function () {
var ParantClass = function () {}
var instance
return function() {
if(instance) {
return instance
}
instance = new ParantClass()
return instance
}
})()
var childA = Parent()
var childB = Parent()
childA === childB // true 在内部用闭包储存实例,并保证只有一个 |
类库封装的要求就是封闭性,对于需要开放的,则使用对应约定使其开启,需要封闭在内的,就藏在闭包之中。 Jquery库使用的就是闭包方式进行的封装,示例如下 (function () { |
编程语言中JAVA是支持将方法声明为私有的,而JavaScript没有这种原生支持,但可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免了非核心的代码弄乱了代码的公共接口 |
我们在封装类库的时候,类库的主要几个特点就是复用性,最好有单独的作用域和变量名,避免使用var定义全局变量他很有可能会影响到Window下的类库,如果使用立即执行函数闭包,就能够为类库创作单独的作用域在Es6我们可以使用class来完成类库的封装 |
封装类库需要做到两点:
第二点,可以暴露一个变量绑定到window上,如下
|
往一个立即执行函数传入this,然后就可以在函数的第一个参数得到全局上下文。然后在不污染全局的情况下,封装方法,用闭包保留私有变量,最后把封装的方法统一放在一个对象里,挂载到全局上下文。
|
类库封装最重要的要求就是不能让类库中的变量污染全局,而这正是闭包的精髓特征。通过即时函数将类库封装在即时函数func中,这样保证了所有的变量在一个独立的空间内,不会污染全局环境,也不会被其他的对象改变内部环境结构。 |
什么是类库呢?就是引入这个类库通过一些约定好的方式去使用类库提供的各种方法。 |
封装类库最重要的就是要避免污染全局作用域,所以可以利用闭包的优点来实现,具体则可以使用立即执行函数将类库的实现封闭在一个内部作用域中,对外只暴露一个对象或者函数给外界调用 |
通过即时函数将需要的变量传入,可以避免污染全局作用域,又可以用闭包将传入参数放置到当前作用域中方便查找 |
将类库打包成自调函数,在vue中global中就是这样的,代码大致如下: |
避免变量污染全局 使用闭包和即时函数
|
|
(function (window) {
var DEBUG = "debug"
function log(v) {
console.log('我会将参数v打印出来', v)
}
window.$ = {
log: log,
}
})(window);
//调用
$.log("dsqwd") |
|
ES6之后,一个类库,它至少是一个文件吧,作为一个模块文件被import,然后在这个文件里面会有各种各样的逻辑,会有一些本地变量。执行完了这些逻辑之后,最终会有导出。 那么这个过程就是通过导出实现了我们所谓的封装性,也就是说,我们屏蔽了内部的实现而暴露出某一些接口。 如果暴露出的接口里面包括了一些函数,然后函数它大概率是会访问到模块内本地的变量的,那么这无形之中,其实就是使用了闭包。 |
封装类库可能会和用户自定义的全局变量名产生冲突 封装的类库还有可能使用在不同的环境中 |
示例代码
原因类库封装一个很重要的点就是不能让类库中的变量污染全局。 |
封装类库最重要的要求就是不能让类库中的变量污染全局,也不能让外部随意修改删除内部代码。 |
首先类库通俗来说是为了完成某些特定功能的代码块,其中包含一些接口、抽象类等等,并且可能运行在多种环境中,因此其中的变量就必须与外部隔离开,要防止变量污染。而即时函数可以开辟一个独立的作用域,如果在即时函数中定义一个的变量被内部函数捕获使用,这个函数就形成了闭包。所以可以利用这一特性,将类库中的变量定义在即时函数中,并在即时函数内部定义函数方法使用这些变量,最后导出定义的方法,以达成类库的封装。 |
将所有的数据和功能都封装在一个函数的内部,只向外暴露一个包含有n个方法的对象或者函数,使用者只需要通过对暴露的对象调用方法来实现相对应的功能,避免了类库中的变量污染全局,也不能让外部随意修改删除内部代码,因此我们可以通过即时函数来进行封装。 |
我们封装类库,要特别注意的就是,尽量的减少和其他模块代码的耦合,体现类库的公共特性,而且要避免变量名的污染。 我们可以利用闭包缓存私有属性的特点,和即时函数作用域隔离的特性,去将类库自己的逻辑和变量缓存在闭包里,只返回一些和外部定义好的方法和对象即可。 如下结构: const lib = (function(){
let obj = {},private = 'abc';
obj.getPrivate = function(){
return private;
}
obj.addtoPrivate = function (val){
return private+val
}
return obj;
})() 也可以如下直接挂在全局 (function (global){
let obj = {},private = 'abc';
obj.getPrivate = function(){
return private;
}
obj.addtoPrivate = function (val){
return private+val
}
window.obj = obj;
})(this) |
类库就是把一些特殊的功能封装到一个函数中,留出一个或多个api的接口给外部函数调用;可以通过闭包的即时函数来实现 |
1.类库封装最重要的要求就是不能让类库中的变量污染全局,我们可以通过构建闭包来实现这种要求。
// 单例需求 singleton |
The text was updated successfully, but these errors were encountered: