什么叫组件化开发
张克军提出的“组件化就是函数式界面开发”这一说法我是难以接受的,函数式界面开发就让它好好地叫“函数式组件化”吧,不然我们会在所谓的“传统UI框架”和“函数式界面开发”之间出现一个Gap,岂不是又要造个词给填上,多累……
我前面说会有一个Gap,这个Gap很可能就是我们现在想用“组件化”这个定义去表达的一些点,我想在此做一些个人的见解
我将之理解为以下几要素:
组件是对逻辑的封装,不限于图形元素。即我们可以把if做成组件、把一个倒计时做成组件、把一段动画做成组件、把路由做成组件、把数据架构做成组件,而这些并不能称为控件
组件具备单个可移植性,即“随加载随用”,不需要为其准备复杂的基础条件(如引入样式、引入框架等)。然而这一点现有那些所谓组件库做得并不好,技术上也不大现实
组件是声明式定义的,而非命令式。这个不想多说,很大程度上是自己主观的一个想法
而上面最重要的就是第一点,所以要问我什么是“组件化开发”,我的说法是:
把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式
这与传统开发框架的最大区别就是统一了图形元素与非图形元素,除此之外我再想不出其它真正体现区别的点了
在这个概念下,包括router、ajax、moduleloader、timer、animation、interval等,都是组件,共享统一的生命周期管理和对外接口,且都是声明式地进行组合
我的一位同事告诉我去年的深JS上,有位淘宝的朋友的话题叫做“前端组件服务化”,这里面提的那些个概念,是很符合我对“组件化”的认识的,他要是不给再强安个“服务化”的噱头就好了–
不过话说回来,在这个要求之下,组件其实不是那么好进行抽象设计的,随便说几个例子,有难的也有简单的:
非图形元素的各种需求如何统一接口,如timer和ajax
组件可以横向组件,但是纵向复用如何解决,如希望任何图形元素都可以实现被鼠标拖拽的效果,则鼠标拖拽应该也是个组件,这个组件与其它组件的关系是什么
有些组件对其可被组合的组件是有要求的,比如HTML里就不大好意思把一个
放进一个里,这一点如何在组件上表达(实现不难,表达比较难)
一些我们原本想当然认为纯的小函数的东西,是不是也能当组件玩,比如underscore.pick要不要也是个组件
如何理解前端模块化
前端模块化
在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀
这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码
既然JavaScript不能handle如此大规模的代码,我们可以借鉴一下其它语言是怎么处理大规模程序设计的,在Java中有一个重要带概念——package,逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部如果使用呢?直接import对应的package即可
importjava.util.ArrayList;
遗憾的是JavaScript在设计时定位原因,没有提供类似的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码,我们称为模块化。
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,各行其是就都乱套了
规范形成的过程是痛苦的,前端的先驱在刀耕火种、茹毛饮血的阶段开始,发展到现在初具规模,简单了解一下这段不凡的历程
我们在讲函数的时候提到,函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块了
functionfn1(){
statement
functionfn2(){
statement
这样在需要的以后夹在函数所在文件,调用函数就可以了
这种做法的缺点很明显:污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间没什么关系。
为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中
varmyModule={
var1:1,
var2:2,
fn1:function(){
fn2:function(){
这样我们在希望调用模块的时候引用对应文件,然后
myModule.fn2();
这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系
看似不错的解决方案,但是也有缺陷,外部可以随意修改内部成员
myModel.var1=100;
这样就会产生意外的安全问题
立即执行函数
可以通过立即执行函数,来达到隐藏细节的目的
varmyModule=(function(){
varvar1=1;
varvar2=2;
functionfn1(){
functionfn2(){
return{
fn1:fn1,
fn2:fn2
})();
这样在模块外部无法修改我们没有暴露出来的变量、函数
上述做法就是我们模块化的基础,目前,通行的JavaScript模块规范主要有两种:CommonJS和AMD
CommonJS
我们先从CommonJS谈起,因为在网页端没有模块化编程只是页面JavaScript逻辑复杂,但也可以工作下去,在服务器端却一定要有模块,所以虽然JavaScript在web端发展这么多年,第一个流行的模块化规范却由服务器端的JavaScript应用带来,CommonJS规范是由NodeJS发扬光大,这标志着JavaScript模块化编程正式登上舞台。
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性
模块输出:
模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象
加载模块:
加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象
如何实现前端模块化开发
在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀
这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码
既然JavaScript不能handle如此大规模的代码,我们可以借鉴一下其它语言是怎么处理大规模程序设计的,在Java中有一个重要带概念——package,逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部如果使用呢?直接import对应的package即可前端如果想做模块化开发,首先需要针对每一种资源(
javascript
、模板等)寻找
一种模块与集成方案,然后需要根据情况的不同选用不同的工具框架拼凑出来。
seajs
是一个适用于
浏览器端的模块加载器。使用
seajs
,可以更好地组织
javascript
不知道别人怎么做的,我自己现在的做法是,基本通用的功能做成一个
style
样式,只需要一个
调用一下就
了,比如图片上传。而一
些常用但不通用的功能做成一组文件,包括
结构还有一个
文件,也可
能还有图片什么的,有时候甚至做成不用调用,直接加载就能用。
至于具体的调用方法,
window
定义一个变量,
放入调用的这个功能的
function
初始化一个模块,
并返回这个模块闭包中的一些方法用来操作或者获取和设置一些模块闭包
内的变量。
javascript
目前比较拿的出手的,也就是
jav可商用的素材网站ascript
的模块化,比如
等等,分别可以使
requirejs
seajs
去年在…前端如果想做模块化开发,首先需要针对每一种资源(
javascript
、模板等)寻找
一种模块与集成方案,然后需要根据情况的不同选用不同的工具框架拼凑出来。
seajs
是一个适用于
浏览器端的模块加载器。使用
seajs
,可以更好地组织
javascript
不知道别人怎么做的,我自己现在的做法是,基本通用的功能做成一个
style
样式,只需要一个
调用一下就
了,比如图片上传。而一
些常用但不通用的功能做成一组文件,包括
结构还有一个
文件,也可
能还有图片什么的,有时候甚至做成不用调用,直接加载就能用。
至于具体的调用方法,
window
定义一个变量,
放入调用的这个功能的
function
初始化一个模块,
并返回这个模块闭包中的一些方法用来操作或者获取和设置一些模块闭包
内的变量。
javascript
目前比较拿的出手的,也就是
javascript
的模块化,比如
等等,分别可以使
requirejs
seajs
去年在研究基于
backbone
marionette
sea.js
结合使用。现在来看这种组合
是完全没有必要的。
marionette
提供了模块化的组织方案,反而生拉硬扯在一起,冲突得很
难受。其实把
javascript
文件一列放在
中也没什么问题。
究竟使用什么来实现
javascript
往往与选择的
javascript
框架有关,
backbone
angularjs
直接引用就行。
模块化应该是两方面的问题——
一是模块必须有一套基础样式。与
javascript
冲突简直是家常便饭,
shadow dom
还没成熟,
样式隔离还在路上。
所以必须有一套基础样式来规定这一套模块化组
件的样式。我们可以选
bootstrap
,如果闲它太重,也可以自己写。
其次,每个组件必须有命名空间,避免组件间样式冲突。如果选择使用
就比较好办,它们的缩进语法避免写很多重复的
angularjs
angularjs
已经帮您解决了模板模块化的问题,
angularjs
可以根据模
块代码中的引用加载对应的
。如果使用
backbone
,可以选择各种各样的模板引擎,
mustache
?不过比起
angularjs
就低端些,我们必须自己处理模板文件,要么通过模块加载
请求,然后动态编译;或者将
mustache
,在当做模块加载。
图片、字体?
放在使用他们的模块中,该怎么引用就怎么引用。
国际化文件?这些就不多说了,总之,每种文件需要选定一种开发的组织方式。
模块采用统一的模式来开发之后,只需选定一种包的分发方式就行了——
bower
合这样的场景,
的版本管理太过细致了。如果同一个项目中允许出现同一模块的不同
版本,事情就做的太过复杂了。
发布上线必须一个以终为始的过程。
如果你不追求网站或者应用的速度,
那就把那些开发文
件直接丢到生产服务器上去吧。别说,我还真见过这样的商用的网站。
如果讲究一些方案,
资源合并成数个文件,
代码线上组合和运行方式完全可以与本地开发不
一样。只需要功能在就行。
javascript
代码打成一个文件,或者两个?都行。如果使用
requirejs
requirejs
包的工具,打包成几个文件,什么粒度,都行。如果是
sea.js
也有对应的工具。就算文件都
是一个一个列出来,我们也总是可以打出来你想要的文件。
等等其他资源都是如此,就算开发时各自不同的结构模式,打包时都是可以打的。
,版本号缓存什么的并不在本文的讨论范围之内。
前端模块没有什么特效药。唯一要遵守的原则就是,
node.js
来讲,每种资源必须要
有一种自己的开发和上线组织方式
node.js
开发和上线都是一致的)
,开发和上线完全可
以是两种方式,
大可不必人云亦云,
只要适合可以随意组合;
css scoped style
用之前,应该有一套基础样式和沙盒(模块样式命名空间)
每个模块中的
如果我们使用的框架是
backbone
注定我们要将
javascript
模块,或者使用模块加载器的插件来实现。如果我们使用
angularjs
angularjs
backbone
中的模块使用
angularjs
grunt
内联到页面中。
模块也没有固定的模式,没有固定的
来解脱我们。我们只能组合现有的工具!
就更不用说了,分开写,使用
来组织?再一次没有固定的模式没有
什么是组件化技术,面向对象开发
面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽..正确说法应该是基于组件开发(component-based development)。 面向对象编程(object-oreinted programming) 是一种编程范式。指在设计程序时大量运用类实例对象的方式。oop一旦在项目中被运用,就成了时刻要考虑的东西。