《编写可维护的javascript》笔记

编写可维护的javascript读书笔记。本书从编码风格、编程实践以及自动化3个部分来讲的。

编码风格

首先引用这部分的开头的一句话:

“程序是写给人读的,只是偶尔让计算机执行一下。”

可以通过JSlint和JSHint(JSlint的分支)帮助团队达成一致的编码风格。

  • 缩进层级:我觉得只要不是混用空格和Tab就行。
  • {}大括号:Jquery分格。
  • 行的长度:不能超过80的字符,总是将运算符置于行尾。
  • 空行:能让代码看起来错落有致,规则:方法之间、局部变量和第一条语句之间、方法内的逻辑片段之间、注释之前。
  • 命名:形如 thisIsMyName 既驼峰命名法,当前主流的编程规范不推荐名字前冠以类型标识符前缀的匈牙利命名法
    1. 变量:名次作为前缀
    2. 函数:动词作为前缀,can,has,is可以作为返回布尔值函数的前缀,set可以作为保存一个值,其他:get
    3. 常量:大写字母加下划线,形如:MAX_COUNT,URL
    4. 构造函数:跟js的内置函数RegExp、Object一样,一大写字母开头的驼峰。
  • 直接量:字符串、数字、布尔值、null和undefined。同样包括对象直接量和数组直接量。只有布尔值是自解释的。
    1. 字符串:可以用单引号也可以用双引号,只要不是单引号和双引号混用就行。多行字符串用 + 相连。如
      var longString = “Here’s the story , of a man “+
      “named Brady”;
    2. 数字:为了避免歧义,不要省略小数点之前活之后的数字和使用八进制写法。
    3. null和undefined:为了确保只有在变量未声明的情况下typeof返回undefined,只在变量将来可能被赋值为对象或者和已经初始化的变量比较的情况下才将其赋值为null。
    4. 对象直接量:直接量{}代替显示创建new Object
    5. 数组直接量:直接量[]代替显示创建new Array
  • 注释:让代码更加理解。在难于理解的代码前、可能被误认为错误的代码前、浏览器hack、文档注释(JSDoc插件)
  • 语句表达式
    					if ( condition ) {
    						// 语句
    					}
    
    					while ( condition ) {
    				    	// 语句
    					}
    
    					for ( var i = 0; i < 10; i++ ) {
    						if (i === 2) {
    							continue; //跳过本次迭代
    						}
    						if (i === 8) {
    							break; //迭代不继续
    						}
    				  		// 语句
    					}
    
    					// 遍历对象属性,
    					for ( var prop in object ) {
    						// 确认没有在原型链上添加属性石可以去掉以下语句
    						if (object.hasOwnproperty(prop)) {
    							// 语句	
    						}
    					}
    
    					if ( true ) {
    				  		// 语句
    					} else {
    				  		// 语句
    					}
    
    					// switch 语句示例
    					switch( foo ) {
    					case "first":
    						// 语句
    						break;
    					case "second":
    						// 语句
    						break;
    					default:
    						// 默认分支
    					}
    				
  • 变量声明:将所有的变量声明放在函数顶部,合并var语句,使用单var语句。
  • 函数声明:函数声明也会被JavaScript引擎提前。在函数声明过后再使用函数。而函数调用函数名和左括号之间没有空格
  • 立即调用的函数:将匿名函数赋值给变量和属性,为了让能一眼就看出函数被赋值给对象,如下格式:
    					var value = (function() {
    						//函数体
    						return {
    							create : createMember //单单把需要能被外部访问的元素的指针返回
    						}
    					}());
    				
  • 严格模式:"use strict"禁止在全局模式下使用严格模式,而是在函数体内。
  • 相等:不管是布尔值还是字符串跟数字比,永远是它们被转换成数字再进行比较。如果其中一个值是对象而另一个不是,则会首先调用对象的valueOf()方法,得到原始类型值再进行比较。==和!=会进行隐式类型转换,建议使用 ===和==
  • eval():给setTimeout、setInterval以及new Function传入字符串能实现跟eval()一样的效果,只有在解析JSON和实在没办法的情况下才使用。
  • 原始包装类型:Strings、Boolean和Number3种原始包装类型。原始包装类型的主要作用是让原始值具有对象般的行为。javascript引擎会在执行诸如toLowerCase()之类的方法时,影式创建响应类型,紧跟着销毁。为了避免开发者在原始值和对象之间跳来跳去,避免使用它。

关于,

基本的格式化

编程实践

同样引用这部分的开头的一句话:

“构建软件的方法有两种:一种是把软件做得很简单以至于明显找不到缺陷;另一种是把它做得很复杂以至于找不到明显缺陷。”

我看这句话怎么像是个笑话呢。如果前一部分讲的是约定代码风格规范,让团队成员之间的看懂各自的代码,这部分讲的是提高代码总体质量的小技巧,有些是由于javascript语言的缺陷,有些则是由于解决HTML、js以及css三者紧耦合。

  • 松耦合:虽然一起工作的组件无法做到“无耦合”,但是如果一个WEB UI是送耦合的,则很容易调试,就很容易找到出错的地方。
  • 将javascript从css中抽离:禁止使用css表达式(expression),css表达式只在IE8和更早版本的浏览器支持。
  • 将css从javascript中抽离:将css写在 className 上,className上的样式则定义在css代码中。element.className += "revael"
  • 将javascript从HTML中抽离:1.按钮点击时,doSomething()函数可能还没加载完,导致错误;2.js中改了doSomething()函数的名字还要在HTML代码里再改一次。
  • 将HTML从javascript中抽离
    1. 从服务器加载,只适用于少量标签段。
    2. 简单客户端模板:利用 %s占位符,javascript将提取定义在HTML中的模板(已注释),然后用数据替换占位符,紧接着就将它格式化最后插入DOM。
    3. 复杂客户端模板:考虑使用 Handlebars
  • 避免使用全局变量:随着代码量的增长,全局变量会导致一些严重的可维护性难题。确保函数不会对全局变量有依赖。
  • 意外的全局变量:只要是变量就必须使用var申明。
  • 单全局变量方式:创建唯一全局对象名(独一无二的),并将所有的功能代码挂载在这个全局对象上。如jQuery中的$。
  • 命名空间:将功能按照命名空间进行分组,可以让你的单全局变量变得更井然有序。如Y.EOM、Y.Event
  • 模块:YUI模块和AMD模块(Dojo、requireJS)
  • 零全局变量:不需要页面中知道他的存在
    					(function(win){
    						// 代码
    					})(window)
    				
  • 事件处理:将应用逻辑和事件处理的代码拆分开来,而应用逻辑不应当一栏event对象。
  • 避免“空比较”
  • 检测原始值
    1. 字符串:typeof 返回 “string”
    2. 数字:typeof 返回 “number”
    3. 布尔值:typeof 返回 “boolean”
    4. undefined:typeof 返回 “undefined”
  • 检测应用值:除了原始值之外的都是应用值。 value instanceof constructor,不仅仅检测这个对象的构造器,还检测原型链。
  • 检测函数:通过 in 运算符检测DOM的方法,其他函数使用typeof检测
  • 检测数组:除了鸭式辨型来检测是sort()方法是否存在,优雅的解决方案:
    					function isArray(value){
    						return Object.prototype.toString.call(value) === "[object Array]";
    					}
    				
  • 检测属性
    1. 使用in运算符来检测实例对象的属性或者继承自对象的原型;
    2. 使用hasOwnProperty检测实例对象的属性;
    3. 使用hasprototypeproperty检测是否继承字对象的原型;

    注意:在调用DOM对象的hasOwnprototype()方法之前应当先检测其是否存在。

  • 配置数据:哪些算配置数据:URL、需要展现给用户的字符串、重复的值、设置、任何可能发生变更的值。
  • 抽离配置信息:可以新建一个config对象,将配置数据抽离出来保存其中,这样任何人都可以修改,而不会导致应用逻辑出错。
  • 保存配置信息:作者喜欢采用java属性文件(java properties file)来保存配置数据,然后将这个文件转换为javascript可用的格式:JSON,JSONP,将JSON对象赋值给一个变量。作者还创建了一个名叫 Props2Js来读取java属性文件并给出以上三种格式的输出。
  • 错误的本质:在可控的范围内,抛出自己的错误,是调试任务更简单。
  • 抛出错误:throw new Error("something bad happened"),推荐在错误信息中包含函数名称以及函数失败的原因,抛出错误是为了更容易调试不是为了防止错误。
  • try-catch:可能引发错误的代码放在try中没处理错误的代码放在catch块中。千万不能将catch块留空,你知道他会错误,为啥不写点什么呢。还可以增加finaly块、finaly块不管是否有错误发生,最后都会执行。
  • 错误类型
  • 不是你的对象就不要动:原生对象、DOM对象、BOM对象、类库的对象。
  • 不覆盖方法:会覆盖其他脚本的方法,会让依赖于该方法的代码都失效。
  • 不新增方法:增加方法一个大问题是将来导致命名冲突。Prototype类库就是个很好的教训。
  • 不删除方法:最简单的删除一个方法的方式是给对象名字的赋值为null。使用delete操作符来删除实力上定义方法。
  • 更好的途径:先继承,然后再新增一些功能。不能从DOM和BOM对象继承;由于数组索引和length属性之间错综复杂的关系,继承自Array是不能工作的。
  • 基于对象的继承:ECMAScript5的Object.create()方法实现这种继承。
  • 基于类型的基础:该继承依赖于原型,基于类型的继承是通过构造函数实现的,而非对象。一般需要两部:原型继承和构造器继承。构造器继承是调用超类的构造函数是传入新建的对象作为器this的值。如:
    					function Person(name){
    						this.name;
    					}
    					function Author(name){
    						Person.call(this,name);  // 继承构造器
    					}
    					Author.prototype = new Person();
    				
  • 门面模式:为已存在的对象创建一个新的接口,所以有时也叫包装器。如下实例:
    					function DOMWrapper(element){
    						this.element = element;
    					}
    					DOMWrapper.prototype.addClass = function(className){
    						element.calss += " " + className;	
    					}
    					DOMWrapper.peototype.remove = function(className){
    						this.element.parentNode.removeChild(this.element);
    					}
    					var wrapper = new DOMWrapper(document.getElementById("my-div"));
    					wrapper.addClass("selected");
    					wrapper.remove();
    				
  • User-Agent检测:因为浏览器并不总是提供它们原始的User-Agent,所以视图去猜测获取到的用户代理字符串是毫无意义的。
  • 特性检测:因为特性检测不依赖于所使用的浏览器,而仅仅依据特性是否存在。有一点要注意的是当被检测的方法不存在使应提供一个合乎逻辑的备用方法。
  • 避免特性推荐:什么是特性推荐:根据一个特性的存在推断另一个特性是否存在。
  • 避免浏览器推断:浏览器推断的问题相当严重,尤其是当有新的浏览器发布时,此时代码需要更新,不然...
  • 浏览器嗅探该如何取舍:作者建议尽可能的使用特性检测。如果不能这么做的时候,可以退而求其次。考虑使用用户代理检测。永远不要使用浏览器推断。

自动化

“我相当乐意花一天的时间通过编程把一个任务实现自动化,除非这个任务手动只需要10秒钟就能完成”

翻了几页发现是用ant构建javascript,所以:

我更乐意用使用更前端的Grunt来构建任务自动化,除非这世上的前端都在使用Ant来构建任务自动化。

本文源链接:http://www.html5jscss.com/maintainable_javascript_note.html

转载请注明《《编写可维护的javascript》笔记》| html5jscss

评论关闭了.