回归本质,从头开始定制适合自己的组件库

工作生活中会有人这样说:“每天工作感觉身体就像被掏空,累得像只狗”。
也有人会那样说:“我真的好喜欢工作,工作让我进步,超快乐”。
作为前端的你,如果也感觉身体被掏空的话,那么首先应该问问自己,是不是肾透支了。如果不是,那你肯定是没有积累自己的组件库吧!。。组件库吧!。。库吧!。。Ccccccccccccccc………….!

其实工作中有很多地方都是可以偷懒的,比如把以前写好的组件直接加载拿来就用,让你的项目开发速度快无边际,简直是开心又惬意,如果再配合GH60机械键盘的话,嗯哼,工作就是一种享受。

言归正转,如何从头开始开发一个JavaScript组件库呢?

IIFE (最古老也是最简单的JS 模块化方法)

IIFE 是最早最有效的一种模块化写法,它被用来封装应用程序的逻辑,保护全局名称空间免受污染。实际上这就是一个匿名函数,被定义后会立即被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;(function(namespace,undefined){
//私有属性
var foo="foo";
//公有方法和属性
namespace.foobar="foobar";
namespace.sayHello=function(){
console.log("sayhello");
}
//在全局命名空间内检测namespace是否存在,如果不存在,给window.namespace赋值一个对象字面量。
})(window.namespace=window.namespace || {});
console.log(namespace.foobar); //输出: foobar
namespace.sayHello(); //输出: sayhello
namespace.foobar2="foobar2"; //赋值新属性
console.log(namespace.foobar2); //输出: foobar2

通过这种形式写自执行函数有一个缺点,就是想看传入的参数需要到代码末尾才能看到,所以又有一种IIFE最佳实践写法。

1
2
3
4
5
(function(factory){
factory(window);
}(function(window){
window.module=module;
}));wo

UMD(通用模块依赖)

如果你的项目只使用jQuery,没有使用模块化打包工具(AMD,CMD,CommonJS),并且以后也不会用,那就跳过这一小节。UMD模式是让你在使用这些模块化工具打包后,引入组件不出错的。具体内从看这里umd

1
2
3
4
5
6
7
8
9
10
11
12
13
;(function (global, factory) {
if(typeof module === "object" && typeof module.exports === "object"){
//CommonJS
module.exports = factory(global,true);
}else if(typeof define === 'function' && define.amd){
//AMD
define([],factory);
}else{
factory(global);
}
}(typeof window!== "undefined" ? window : this, function () { //用于判断当前执行环境是否支持window类型,是的话返回window,否则返回this
//.....
});

构造方法、静态方法

最开始接触这些的时候,我整个人都是崩溃的,为什么自己家的实例化代码要new zzk().xxx(),这样看起来一点也不美观,不像别人家的代码 $.each() ,简单粗暴美观。后来才知道,别人家的代码是封装了一个构造器,然后使用了静态与实例方法共享的设计,当时还是太年轻啊,直接上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var zzk= function(selector){
//把原型上的init作为构造器
return new zzk.prototype.init(selector);
}
zzk.fn= zzk.prototype={
constructor: zzk,
init: function(selector){
return this;
},
//这是实例方法,调用静态方法,也就是静态与实例共享
each: function(){
return zzk.each();
}
}
//把 zzk.fn.init 的原型指向 zzk 的原型,不这样做会导致zzk实例对象无法访问原型属性或方法
zzk.fn.init.prototype= zzk.fn;
//这是静态方法,不需要实例化就可以调用
zzk.each=function(){
//.......
}

基于jQuery的回调写法

回调函数在组件开发中使用非常频繁,因为组件是对常用功能抽象出来加以实现的,为了保证可以在不同的项目中都适用,就不会加入业务逻辑代码,那业务逻辑代码放在哪里呢?答案就是回调函数里,这其实就是异步编程最基本的方法,下面给出一个基于jQuery的Promises异步写法,供大家参考学习。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
f1().then(f2).then(f3);
function f1(){
var dfd= $.Deferred();
setTimeout(function(){
dfd.resolve();
},5000);
return dfd.promise();
}
function f2() {
alert('a');
}
function f3() {
alert('b');
}

最后有个Demo代码在我的Github上,有兴趣的同学可以看一下。

请zkzhao喝杯咖啡作为鼓励!