聊聊前端领域那些“门面”
时间:2023-03-22 16:51:56
科技观察
再来说说前端领域的“门面”。转载本文请联系神光编程秘籍公众号。门面模式(Facade)是23种经典设计模式之一,又称外观模式,通过在客户端和子系统之间引入一个中间层,隐藏了内部的复杂性,暴露出简单易用的界面。引入门面模式后,客户端使用起来会方便很多,不再需要了解具体的细节。比如在使用门面模式之前,可能是这样的调用关系。客户需要知道每一个内部细节。使用facade模式后,client不再需要知道具体的模块,只需要告诉Facade自己的需求即可。然后它调用内部模块并添加一个外观。它会改变功能吗?不,它只是使外部接口更易于使用。而这就是门面模式的意义:封装内部细节,简化调用。其实在软件领域这样的门面太多了。包括html、css、vue模板、react的jsx在内的各种DSL(领域特定语言)都是门面。,babel和eslint的presets也是门面。下面分别分析一下。简化dom创建的外观:html浏览器提供了domapi,基于domapi我们可以构建dom树,为什么我们需要html?没有html可以吗?比如domapi创建dom:constdiv=document.createElement('div');div.className="a";constimg=document.createElement('img');img.src="./b.jpg"div.appendChild(img);和htmldescriptiondom:
两者没有区别。所以,html并没有增加功能,只是简化了dom操作,这显然是一种门面模式,而是通过DSL。DSL是指一种领域特定的语言,设计一种语法来简化逻辑的描述,然后解析语言来具体描述目标。浏览器通过解析html来构建dom树。简化样式描述的门面:csscss也是dsl的一种,目的是为了简化样式信息的描述。比如直接给dom添加样式会比较麻烦:constdiv=document.querySelector('.a');div.style.backgroundColor='blue';constimg=div.querySelector('img');img.style。border='2px';而通过css添加就简单多了:.a{background-color:blue;}.aimg{border:2px;}css是否增加了新的功能?不,它只是使样式描述更容易。同样,css这个dsl??也是被浏览器解析的。对于vue的模板,我们知道基于domapi来操作视图就足够了。前端框架就是把数据映射到视图上,映射的对象也是domapi(当然中间还有一层虚拟dom,所以也先创建了api。虚拟dom),但dsl没必要选择使用html,可以用其他更适合自身特点的方式来描述。vue选择模板:如果直接用api描述view不够直观:render:function(createElement){returncreateElement('h1',this.blogTitle)}vue选择模板,类似html:
{{blogTitle}
这并没有增加功能,只是让开发者更容易使用框架来描述视图,而且vue还支持过滤器、指令、插值语法等功能。但是在引入模板dsl的时候,需要编译。不同于html是由浏览器解析的,这个自定义的dsl需要自己的编译器来解析,所以vue内部有一个template编译器,将template转化为render函数。React的jsxreact也需要将view的描述映射成真实的dom(中间还有一层虚拟dom)。首先,它会提供API的方式,但是为了简化使用,它会提供一种描述视图的方式:jsx。直接用api比较麻烦:consttitle=React.createElement("h1",{className:"main"},"HelloReact");jsx的方式就简单多了:consttitle=(
HelloReact
);vue和react选择不同的dsl。我们知道dsl需要编译成具体的api调用,vue是框架内部实现的,react的jsx是babel实现的(因为是js语法的扩展)。可以看出无论是vue的template还是react的jsx都没有增加新的功能。加这么一层dsl只是为了简化开发者对view的描述。符合html的设计目的,是门面模式的思想。babel的presetbabel是用来进行代码转换的。它将esnext的语法转换为目标环境支持的js语法。具体的转换是通过插件来完成的。但是开发者直接指定插件太麻烦了。比如es2015有一系列的插件,es2016有一堆。如果开发者指定的话,使用起来会很复杂。所以babel设计了一个preset。babel6的presets有preset-es2015、preset-es2016等,都是里面的一系列插件。而babel7进一步简化为preset-env,只要通过targets指定目标环境,就会自动选择一系列插件使用。预设是否实现了任何新功能?不,最终的转换还是由插件来完成。但是preset简化了开发者使用babel的成本,所以这也是一种典型的门面模式。综上所述,门面模式是软件领域非常普遍的一种模式。当暴露给客户端的子系统特别复杂时,通过增加一层门面,处理具体的子系统,隔离复杂性,让软件的使用变得简单。通过隔离复杂性,复杂性得到很好的管理,否则随着迭代使用可能会变得越来越复杂。前端领域常见的html,css,还有vue的tempalte,react的jsx都是dsl。dsl的目的是简化调用,是门面模式的典型实现。(template和jsx需要自己编译,而html和css是浏览器编译的)。此外,还引入了babel、eslint等presets来简化使用成本,否则用户将直接面对各种复杂的插件配置。门面模式不引入新的功能实现,只是一个入口,简化系统使用成本。如果遇到特别复杂的系统,不妨通过引入门面(以api或dsl的形式封装)来简化它。