声明式编程
声明式编程
声明式编程是以数据结构的形式来表达程序执行的逻辑。它的主要思想是告诉计算机应该做什么,但不指定具体要怎么做。SQL 语句就是最明显的一种声明式编程的例子,例如:
SELECT * FROM collection WHERE num > 5
通过观察声明式编程的代码我们可以发现它有一个特点是它不需要创建变量用来存储数据。另一个特点是它不包含循环控制的代码如 for,while。函数式编程和声明式编程是有所关联的,因为他们思想是一致的:即只关注做什么而不是怎么做。但函数式编程不仅仅局限于声明式编程。
Web 上的声明式查询
除了 SQL,网页编程中用到的 HTML 和 CSS 也都属于声明式编程。假设你有一个关于海洋动物的网站。用户当前正在查看鲨鱼页面,因此你将当前所选的导航项目“鲨鱼”标记为当前选中项目。
<ul>
<li class="selected">
<p>Sharks</p>
<ul>
<li>Great White Shark</li>
<li>Tiger Shark</li>
<li>Hammerhead Shark</li>
</ul>
</li>
<li>
<p>Whales</p>
<ul>
<li>Blue Whale</li>
<li>Humpback Whale</li>
<li>Fin Whale</li>
</ul>
</li>
</ul>
现在想让当前所选页面的标题具有一个蓝色的背景,以便在视觉上突出显示。使用 CSS 实现起来非常简单:
li.selected > p {
background-color: blue;
}
这里的 CSS 选择器li.selected> p
声明了我们想要应用蓝色样式的元素的模式:即其直接父元素是具有selected
CSS 类的元素的所有
元素。示例中的元素Sharks
匹配此模式,但Whales
不匹配,因为其``父元素缺少class =“selected”
。
如果使用 XSL 而不是 CSS,你可以做类似的事情:
<xsl:template match="li[@class='selected']/p">
<fo:block background-color="blue">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
这里的 XPath 表达式li[@class='selected']/p
相当于上例中的 CSS 选择器li.selected> p
。CSS 和 XSL 的共同之处在于,它们都是用于指定文档样式的声明式语言。
想象一下,必须使用命令式方法的情况会是如何。在 Javascript 中,使用 文档对象模型(DOM) API,其结果可能如下所示:
var liElements = document.getElementsByTagName("li");
for (var i = 0; i < liElements.length; i++) {
if (liElements[i].className === "selected") {
var children = liElements[i].childNodes;
for (var j = 0; j < children.length; j++) {
var child = children[j];
if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "P") {
child.setAttribute("style", "background-color: blue");
}
}
}
}
这段 JavaScript 代码命令式地将元素设置为蓝色背景,但是代码看起来很糟糕。不仅比 CSS 和 XSL 等价物更长,更难理解,而且还有一些严重的问题:
- 如果选定的类被移除(例如,因为用户点击了不同的页面),即使代码重新运行,蓝色背景也不会被移除 - 因此该项目将保持突出显示,直到整个页面被重新加载。使用 CSS,浏览器会自动检测
li.selected> p
规则何时不再适用,并在选定的类被移除后立即移除蓝色背景。 - 如果你想要利用新的 API(例如
document.getElementsBy ClassName(“selected”
)甚至document.evaluate()
)来提高性能,则必须重写代码。另一方面,浏览器供应商可以在不破坏兼容性的情况下提高 CSS 和 XPath 的性能。
在 Web 浏览器中,使用声明式 CSS 样式比使用 JavaScript 命令式地操作样式要好得多。类似地,在数据库中,使用像 SQL 这样的声明式查询语言比使用命令式查询 API 要好得多。