首页 > 代码库 > 读书笔记之《The Art of Readable Code》Part 3
读书笔记之《The Art of Readable Code》Part 3
如何重新组织代码提高可读性? (函数层面, part 3)
1. 抽取与主要问题无关的代码
2. 重新组织代码使得一次只做一件事
3. 首先描述功能,然后再实现功能,这样更清楚明了
如何抽出问题无关的子问题? (chap 10)
0. 无关问题的思考
- 看到一个函数或一个代码块, 问自己, "这段代码的高层作用是什么(high-level gloal)"
- 对于每一行代码, 思考"它是直接解决这个目标吗",还是"解决一个子问题来达到目标的解决"
- 如果是解决子问题,并且代码的行数也足够多,那么就可以抽取出一个独立的函数
// Return which element of ‘array‘ is closest to the given latitude/longitude.// Models the Earth as a perfect sphere.var findClosestLocation = function (lat, lng, array) { var closest; var closest_dist = Number.MAX_VALUE; for (var i = 0; i < array.length; i += 1) { // Convert both points to radians. var lat_rad = radians(lat); var lng_rad = radians(lng); var lat2_rad = radians(array[i].latitude); var lng2_rad = radians(array[i].longitude); // Use the "Spherical Law of Cosines" formula. var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) + Math.cos(lat_rad) * Math.cos(lat2_rad) * Math.cos(lng2_rad - lng_rad)); if (dist < closest_dist) { closest = array[i]; closest_dist = dist; } } return closest;};// Good : clear, easy to test spherical_distance in isolationvar spherical_distance = function (lat1, lng1, lat2, lng2) { var lat1_rad = radians(lat1); var lng1_rad = radians(lng1); var lat2_rad = radians(lat2); var lng2_rad = radians(lng2); // Use the "Spherical Law of Cosines" formula. return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.cos(lng2_rad - lng1_rad));};var findClosestLocation = function (lat, lng, array) { var closest; var closest_dist = Number.MAX_VALUE; for (var i = 0; i < array.length; i += 1) { var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude); if (dist < closest_dist) { closest = array[i]; closest_dist = dist; } } return closest;};
* 纯粹的Utility代码 (比如操作字符串,hash表,读写文件)
这类代码最好封装到一个独立的Util类或者函数,(ReadFileToString())
* 其他通用的代码
ajax_post({ url: ‘http://example.com/submit‘, data: data, on_success: function (response_data) { var str = "{\n"; for (var key in response_data) { str += " " + key + " = " + response_data[key] + "\n"; } alert(str + "}"); });}// Continue handling ‘response_data‘ ...// Good : 函数名更容易定位,更容易维护var format_pretty = function (obj) { var str = "{\n"; for (var key in obj) { str += " " + key + " = " + obj[key] + "\n"; } return str + "}";};// Better : 功能更强大var format_pretty = function (obj, indent) { // Handle null, undefined, strings, and non-objects. if (obj === null) return "null"; if (obj === undefined) return "undefined"; if (typeof obj === "string") return ‘"‘ + obj + ‘"‘; if (typeof obj !== "object") return String(obj); if (indent === undefined) indent = ""; // Handle (non-null) objects. var str = "{\n"; for (var key in obj) { str += indent + " " + key + " = "; str += format_pretty(obj[key], indent + " ") + "\n"; } return str + indent + "}";};
* 创造更多通用功能的代码
像之前的ReadFileToString(), format_pretty()都可以夸工程使用他们
* 工程特有的功能 (即使如此,依然可以考虑创建在工程内部使用的util类/函数)
* 简化现有的接口 (用到某个第三方的库,它的接口不好用,可以考虑对它封装一下)
- Simplifying an existing interface
- Reshaping an interface to your needs
- Don‘t take things too far (不要将一个函数实现细分成太多的小函数,控制粒度)
一次只做一件事情(chap 11, one task at a time)
0. 一个代码片段只做一件事情 (空行风格的代码段)
示例1
// Bad : two things doing together (parseValue, computeScore)var vote_changed = function (old_vote, new_vote) { var score = get_score(); if (new_vote !== old_vote) { if (new_vote === ‘Up‘) { score += (old_vote === ‘Down‘ ? 2 : 1); } else if (new_vote === ‘Down‘) { score -= (old_vote === ‘Up‘ ? 2 : 1); } else if (new_vote === ‘‘) { score += (old_vote === ‘Up‘ ? -1 : 1); } } set_score(score);};// Good : clear to understandvar vote_value = http://www.mamicode.com/function (vote) {>
示例2
// Bad : 不方便扩展var place = location_info["LocalityName"]; // e.g. "Santa Monica"if (!place) { place = location_info["SubAdministrativeAreaName"]; // e.g. "Los Angeles"}if (!place) { place = location_info["AdministrativeAreaName"]; // e.g. "California"}if (!place) { place = "Middle-of-Nowhere";}if (location_info["CountryName"]) { place += ", " + location_info["CountryName"]; // e.g. "USA"} else { place += ", Planet Earth";}return place;// Goodvar town = location_info["LocalityName"]; // e.g. "Santa Monica"var city = location_info["SubAdministrativeAreaName"]; // e.g. "Los Angeles"var state = location_info["AdministrativeAreaName"]; // e.g. "CA"var country = location_info["CountryName"]; // e.g. "USA"// Start with the default, and keep overwriting with the most specific value.var second_half = "Planet Earth";if (country) { second_half = country;}if (state && country === "USA") { second_half = state;}var first_half = "Middle-of-Nowhere";if (state && country !== "USA") { first_half = state;}if (city) { first_half = city;}if (town) { first_half = town;}return first_half + ", " + second_half;// Better : 利用js语法的a||b||c的特性var first_half, second_half;if (country === "USA") { first_half = town || city || "Middle-of-Nowhere"; second_half = state || "USA";} else { first_half = town || city || state || "Middle-of-Nowhere"; second_half = country || "Planet Earth";}return first_half + ", " + second_half;
读书笔记之《The Art of Readable Code》Part 3