BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

w3ctech 2011 JavaScript专题会议(上海站)​综述

| 作者 崔康 关注 0 他的粉丝 发布于 2011年10月18日. 估计阅读时间: 19 分钟 | 如何结合区块链技术,帮助企业降本增效?让我们深度了解几个成功的案例。

w3ctech 2011 JavaScript专题会议(上海站)​最近在张江畅星大厦召开,参会者200多人,来自国内技术社区的四位知名专家高博、权一、杜欢、贺师俊分别做了精彩的演讲,涉及的内容包括测试驱动开发、ES5新特性、iOS上的Web应用、Javascript框架API设计思想等。InfoQ中文站整理了大会的精彩内容,供读者参考。

测试驱动的JavaScript开发入门

来自盛大创新院的高博以自己翻译的书“测试驱动的Javascript开发”为背景,结合在测试工作中的实践经验,介绍了测试驱动在Javascript开发中的应用。

什么是测试驱动开发?高博指出,在传统的开发过程中,大家遵循着先开发后测试的阶段模式,按部就班地需求分析、设计、开发、测试、发布。而在测试驱动开发过程中,测试环节位于开发环节之前,甚至取代了设计环节。测试用例代码完成在先,实际产品代码完成在后,这意味着第一行代码是测试用例代码。测试的结果是开发进度的指挥棒,测试推进到哪里,开发才能跟进到哪里。测试的结果是“失败“,才能继续进行开发工作,直至测试的结果成为”通过“为止。

高博举了一个有关Javascript的测试驱动例子,需求是”开发一个JavaScript字符串函数,实现去除字符串开始和结尾的空白字符的功能”。如何编写第一个测试用例?他认为首先要对需求分解,在这个例子中,可以把”开头“和”结尾“当成两个小的需求,另外不能忽略隐含的需求,比如假定被测试的函数名为trim,那么第一个测试用例可能是判断其在作用域中是一个函数:typeof "".trim == "function"。回到刚才分解的两个需求上来,针对每一个需求写一个测试用来,第一个看起来像这样:

"test trim should remove leading white-space":
 function ()  {
    assert("should remove leading white-space",
    "a string" === " a  string".trim());
 }

即测试去掉开头的空白字符。接下来,运行该测试用例,因为没有还没有定义trim,所以测试结果是失败的,不过在测试驱动的开发中,测试用例的失败结果才是开发能够跟进的唯一动力。可是,为什么明知道测试会得到失败结果,还是要运行一次测试用例?高博指出,这样做的一个原因是测试在当前作用域下存在函数冲突。

接下来实现第一个小需求:

String.prototype.trim = function () {
   return this.replace(/^\s+/,  "");
};

高博特别强调,在开发产品代码时,要暂时忘掉原始的需求,现在的唯一目的是让当前测试用例的结果从失败变成通过。在通过了第一个小需求之后,编写第二个测试用例,并修改产品代码使其通过第二个测试。在每一步撰写了更多产品代码后,高博提醒开发人员要做两件事:

  • 把所有之前的测试用例都要运行一次,并且要全部得到通过结果。这样做可以发现由于代码更改而引入的新问题。
  • 随时对代码进行重构,以保证用更好的等价代码实现同样的目的。

最终的函数定义为:

String.prototype.trim = function() {
   return  this.replace(/(^\s+)|(\s+$)/, "");
};

在测试驱动开发中,存在着一个循环,即”撰写引起新的失败结果的测试用例“——>”撰写新的产品代码以使之前的测试用例通过“——>”重构以得到更好的等价产品代码“——>”撰写引起新的失败结果的测试用例”——>......在这里,测试用例是循环的第一推动力,测试用例在每轮循环的起始代表着需求分析的分解结果,开发过程表现为满足测试用例的活动,测试用例在每轮循环的结束代表着开发规格。高博总结说,测试驱动将难以估算的抽象需求转换为一系列明确的、无二义性的规格。由测试驱动的开发过程是增量式的,由测试驱动的开发无须等到全部的需求明确即可开始,遵循不做无用功原则。测试驱动的本质是将测试用例分别作为需求和规格加入开发过程首末两端的持续集成技术。

为什么要将测试驱动的开发方法引入JavaScript开发呢?高博分析了Javascript语言的特点:极其灵活,书写风格几乎无穷无尽;操作对象复杂,需要面对各种物理和逻辑对象;可以和各种动态语言混合,作为它们的就地(in-place)输入或输出;虽然有标准可循(ECMA-262),但是各种环境对标准支持的程序区别很大;解释型语言,调试的工具和手段比较缺乏。由此导致开发人员容易防御性地过度设计,在开发过程中对产品代码的信心不足。而这些不足恰好是测试驱动开发的用武之地:科学地设计测试用例及其自动化,逐步覆盖需求;每通过一个或一组测试,开发者信心就增强一分。

对于单元测试,高博建议:积累测试用例集,形成回归测试的规模和覆盖率;欲修改产品代码,首先更新测试用例;测试用例彼此独立,避免耦合;只测试 JavaScript,不测试与外部依赖项目的耦合部分(数据库、文件系统、用户界面等);测试用例的建立要多快好省;产品代码要避免形成测试障碍和阻塞(如弹出对话框、Ajax异步调用等)。

对于性能测试,高博认为通过Javascript性能测试,开发人员能够在问题的多种解决方案中,比较优劣。性能测试结果使JavaScript的开发避免了盲目“优化”性能,以及无限制地“改进”性能。

对于当前火热的Node.js技术,高博介绍了NodeUnit工具,并提供了测试示例。除此之外,他还介绍了Stub和Mock,Stub能够像真实的被测试环境一样提供根据输入给出对应输出的模拟对象。通常实现比真实对象要简单,但是从给定的测试用例集合的输出结果看不出它与真实对象的区别。Mock是一种输出结果预知的测试对象。Stub仍然是先执行测试,再得到输出(该结果可能是受控的),而Mock则是直接给出测试输出。Mock对象常用于测试的输出结果不常见的场景,以求得更高的测试覆盖率。

ECMAScript Edition5 尝试

来自盛大在线的Web前端工程师权一为大家讲解了ECMAScript 5引入的重要新特性,虽然该版本早在2009年12月份已经发布,但是由于浏览器的兼容性问题,一直让大家对ECMAScript 5敬而远之。随着浏览器版本的更新,特别是最近Node.js的兴起(其依赖的V8引擎支持ECMAScript 5),开发人员开始尝试应用于实践中。权一目前正在对ECMAScript 5规范进行中文注解,所以他的讲座内容很全面。

目前,ECMAScript 5的支持情况较好的浏览器包括Firefox4+、Chrome11、IE10PP2,还有后端JS运行时NodeJS(V8)。

权一首先分析了ECMAScript 5引入的新API,包括:

  • Object.create(prototype, descriptors)——创建一个对象,指定其prototype,而且可以包含若干描述符对象。
  • Object.defineProperty(object, propertyname, descriptor)——为对象增加属性(property),或者修改现有属性的配置(attribute)。
  • Object.freeze(object)——禁止现有对象属性的配置和值的更改,并禁止增加新属性。
  • Object.seal(object)——禁止现有对象属性的配置的更新,并禁止增加新属性。
  • Object.keys(object)——返回对象中可枚举的属性和方法。
  • Object.preventExtensions(object)——禁止增加对象的属性。

 在这些API中,经常会遇到一个概念,即属性描述符。它是用于解释某一个被命名的属性具体操作规则的特性集。 属性描述符中的对应每个字段名都会有一个值,其中任何一个字段都可以缺省或显式的设置。 属性描述符还会被进一步以字段的实际用途来分类成数据属性描述符访问器属性描述符。比如,在Object.create和 Object.defineProperty方法的参数中会涉及到属性描述符。 

数据属性可以可以存储和获取值,其描述符包括:

  • value——属性的当前值,缺省为undefined。
  • writable——true或者false。如果为true,属性值可以被修改。缺省为false。
  • enumerable——true或者false。如果为true,属性可以在for…in语句中被枚举。缺省为false。
  • configurable——true或者false。如果为true,属性描述符可以被修改,属性可以被删除。缺省为false。 

数据属性的代码示例如下: 

   var  obj = {}; 
     Object.defineProperty(obj, "newDataProperty",  { 
       value: 101, 
       writable: true, 
       enumerable:  true, 
       configurable:  true 
   }); 

访问器属性(accessor)在每次存储或者获取属性值时都会调用用户提供的函数,描述符包括:

  • get——返回属性值的函数,无参数,缺省为undefined。
  • set——函数包含一个参数,即传递的值,该函数用于设置属性值,缺省为undefined。
  • enumerable和configurable的设置与数据属性描述符类似。 

访问器属性的示例代码如下: 

     var  obj = {}; 
     Object.defineProperty(obj, "newAccessorProperty",  { 
       set: function (x) { 
           document.write("in property set  accessor" + newLine); 
           this.newaccpropvalue =  x; 
       }, 
       get: function () { 
           document.write("in  property get accessor" + newLine); 
           return  this.newaccpropvalue; 
       }, 
       enumerable:  true, 
       configurable:  true 
   }); 

权一指出,新增加的Object.create、defineProperty、freeze、seal、preventExtensions等方法会让开发人员在使用Javascript进行面向对象编程时更加方便。 

ECMAScript 5还引入了严格模式(use strict),能够更好地执行错误检查。use strict可以声明一个文件、程序或者函数,这种声明方式称之为指令序言,它的作用域可以是整个程序,也可以是某个函数体内。 

严格模式限制的内容主要包括:

  • 使用未声明的变量。
  • 对只读属性进行赋值操作。
  • 对不可扩展对象增加属性。
  • 在对象中重复定义同一个属性。
  • 使用预留的关键字作为变量名或者函数名。
  • 使用with语句。

 Build Web Apps for iOS

 Cisco CSG前端架构师杜欢的演讲题目是《Build Web Apps for iOS》,不过从其讲座内容来看,是以iOS为例,讲述了Web应用在CSS3、HTML5、UI设计思想中的经验。

 对于设计原则,杜欢强调了以下几点:

  • 保持干净整洁的风格
  • 保持UI元素的一致性
  • 谨慎处理渐进增强 

在实现设计风格时,我们需要重点考虑的地方是这个应用的目的是什么,所有的设计是否为此而存在,所有呈现给用户的功能是否是用户期望的,不走“混搭风”。保持UI的一致性能够降低用户的学习成本、增强应用的整体性。在渐进增强处理时,需要考虑设备的输入输出和特性支持,以及不同浏览器的差异。 

杜欢以iOS设备为例,使用条件式CSS来指定特定样式:

<link media="only screen and (max-device-width: 480px)"  href="small-device.css" type= "text/css" rel="stylesheet">

对于页面的视窗(Viewport)设定,可以参照设备的显示宽度:

<meta name ="viewport" content = "width = device-width">

杜欢还提到了在wifi不工作的离线状态下,如何开发离线应用,即利用缓存清单MANIFEST:

MIME type = text/cache-manifest
<html manifest=“resource.manifest”>

如果需要存储离线数据,则可以通过离线存储,如本地存储WEB Storage、WEB SQL、IndexedDB。
在演讲最后,杜欢总结了iOS开发中需要注意的一些限制:

  • 解码后的GIF, PNG, TIFF图片尺寸不超过3M(width * height ≤ 3 * 1024 * 1024)。
  • 解码后的JPG图片最大尺寸不超过32M像素(使用二次抽样)。
  • Canvas元素的最大尺寸不超过3M像素。
  • Canvas元素的默认宽高为:150 x 300。
  • 单个HTML, CSS, JS或非流媒体格式的资源文件必须小于10M。
  • 任意一段JavaScript执行时间不超过10秒。
  • 一个page要load的所有资源总大小保持在30M以内。
  • 请使用ECMAScript 3。

关于JavaScript库和框架的API设计的思考两三例 

资深Web开发专家贺师俊在讲座中对API的设计和评判标准做了深入的探讨。他首先借用了《软件框架设计的艺术》中的“无绪”(Cluelessness)概念,软件工程中的无绪是指:程序员无需深入了解很多内容,也可写出好的代码找到一种编程实践方法,让开发人员不用深入了解所有事情,即选择他们所需的知识。API是对所需知识的抽象,它将系统的复杂性隐藏起来。 

评价API好坏的标准包括:

  • 可理解性
  • 一致性
  • 可见性
  • 简单性
  • 保护投资(兼容性) 

贺师俊以jQuery为例,其中的Selector体现了可理解性,$体现了可见性,而相比Dojo、YUI,jQuery在兼容性方面表现出色。接着,他又举了Pyhon框架、Grails、Prototype.js、短命名等例子来分析API的设计问题,让读者有了更深的理解。他用较长的篇幅分析了 Lazy function模式在API设计方面的缺陷,并强调不能以防御式编程和提供文档为借口来降低API的质量。 

最后,贺师俊总结API设计的一些经验:

  • API的目的是让开发者可以选择性无绪。
  • 评价API的好坏就是从“选择性无绪”出发,以此衍生出可理解性、一致性、可见性、简单性、保护投资(兼容性)等标准。
  • 即使是看似主观的风格问题,也是可能按照标准结合情境进行分析的。
  • 注意JavaScript的一些特点导致的特殊问题,如prototype,如动态语言特征,如ES5、Harmony新特性带来的API设计的进化等。

 没有参会的朋友可以通过主办方w3ctech相关页面下载幻灯片和观看演讲视频。InfoQ中文站将继续关注国内Web技术社区的发展。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT