2.2 按段落组织代码
在编排代码的时候,要以清晰明白为目标,而不是减少代码的字节数
该有的空格、空白都不能少
- 按逻辑段落组织代码,段落之间要空行
- 每一行最多只包含一条语句或赋值语句,但是允许每行同时声明多个变量
- 运算符和变量之间要有空格,更容易地识别变量
- 每个逗号之后要有空格
- 在段落内,相似的运算符要对齐
- 缩进注释,缩进量和所解释的代码相同
// 把一个或多个声明放在一行上,但每行只有一条赋值语句
let
z, x, c, v, d,
a = l,
b = 2,
arr = [1, 2, 3],
obj = {aa: 1, bb: ''张三"},
name = "法外狂徒张三"
;
// 在下一行段落的前面添加空行
// 函数将文本写入消息容器
print_msg = function ( msg_text ){
// 缩进注释,和它所描述的段落层级一致
// .text() 防止xss注入
$('#sl').text( msg_text );
};
// 函数返回随机数
get_rangdom = function ( num_arg ){
return Math.random() * numn_arg;
};
// 初始化值
x = get_random( 10 );
y = get_random( 20 );
r = get_random( 360 );
// 添加空白,对齐相似的元素,相似的语句更容易阅读
x += 10 + num;
y -= 20 - num;
2.3 换行要一致
- 在运算符的前面换行,开发者检查更加方便
- 把后续的语句缩进一个层次,比如使用两个空格
- 在逗号分隔符的后面换行
- 方括号或者括号单独占一行。清楚地表明这是语句的结尾,不会迫使读者横向扫寻分号
// 将运算符放在左边,排成一列
let str = '我知道你也在向我靠近,'
+ '星河万顷都是你的见面礼。'
+ '所以我也走向了你,'
+ '暮色千里皆是我的回礼。'
+ '今夜星光月夜皆归你,我也归你~'
// 方括号单独占一行,下一条语句就容易识别了
// 使用尾部逗号,更容易维护
let addressArr = [
'湖南省', '湖北省', '广西省',
'江西省', '江苏省', '内蒙古自治区',
'台湾省', '澳门, '香港',
];
3. 命名规范
3.1 变量
命名规则
- 变量名使用a - z、A - Z、0 - 9、下划线和$符号
- 变量名不要以数字开头
- 语义化(看其名,知其意)
作用域
- 当变量作用域是整个模块时使用驼峰式(模块名字空间的所有地方都可以访问该变量)
- 当变量作用域不是整个模块时使用下划线 (模块名字空间内的某个函数的局部变量)
- 确保所有模块作用域内的变量至少有两个音节,这样作用域就会很清晰(例如下:)
- 用户中心 ⇒ userCenter
- 商品列表 ⇒ goodsList
- 消息通知 ⇒ messageInfo
- 再来一组例子:
变量初始名 | 局部作用域 | 模块作用域 |
---|---|---|
str | direction_str | directionStr |
id | goods_id | goodsId |
msg | user_msg | userMsg |
- 全局变量用 const 定义,常量性质,字母全部大写(尽量少定义)
3.2 命名空间
- 早期的JavaScript代码比较简单,单独在一张页面上使用,所以大部分时间不需要考虑命名空间的问题,使用全局变量,而不会有什么影响。
- 但是随着JavaScript应用的蓬勃发展和第三方类库的普遍使用,全局变量的数据可能会急剧上升
- 地域之门从此便开启了。(比如,当两个代码库声明了相同的全局变量时)
- 使用单一的全局函数,把其他所有变量的作用域限制在该函数里面,就可以极大地减少这种问题
// 模拟一个第三方库 => jQuery
(function(window){
// 此变量只会在此区域生效,使用完之后垃圾回收机制自动回收
// 不会污染全局变量
let jquery = {};
})(window)
- 命名空间的细粒度划分
// 在 jquery.js 中
let jquery = (function () {
// some code here
}());
// 在 jquery.dom.js 中
let jquery.dom= (function () {
// some code here
}());
// 在 jquery.css.js 中
let jquery.css = (function () {
// some code here
}());
4. 松耦合,高复用
4.1 什么叫耦合?
- 指一程序中,模块及模块之间信息或参数依赖的程度(官方解释)
- 举个例子:
- 多个零件在一起,组成了一辆车,各零件之间存在耦合
- 电脑主机与显示屏,存在耦合
- 在程序语言中,也会有耦合,比如A模块依赖于B模块
- 我们通常是不需要耦合度很高的,除非特定组件,这样才可以达到高复用
- 举个例子,比如布加迪的轮胎,是找米其林高度定制的,只能适用于布加迪车型,其它品牌车型是用不了的(耦合度越高,复用性越低)
- 而电脑主机与显示器,一般耦合度就很低了,A品牌电脑主机可以用B,C,D品牌各型号的显示器,所以复用性高,可以自由组合。
4.2 松耦合
- 当修改一个组件而不需要更改其他组件时,就做到了松耦合
- 耦合度视情况而定,复用性组件必须低耦合
如何松耦合?
- 将JS从CSS中抽离:不要使用CSS表达式
//不好的做法
.box{width: expression(document.body.offsetWidth + ’px')}
- 将CSS从JS中抽离:通过JS修改CSS样式时,使用className或classList,不要逐条修改style样式
//不好的做法一
ele.style.color = 'red';
ele.style.left= '10px';
//不好的做法二
ele.style.cssText ='color:red;left:10px;';
.reveal{color:red;left:10px;}
//好的做法一
ele.className += 'reveal';
//好的做法二
ele.classList.add('reveal');
- 将JS从HTML中抽离:从JS文件放入外置文件中
- 将HTML从JS中抽离:不要在innerHTML中拼接DOM结构,而是使用字符串模板,如handlerbars
5. 函数优化
5.1 提炼函数
- 在javascript开发中,大部分时间都在与函数打交道,所以希望这些函数有着良好的命名,函数体内包含的逻辑清晰明了。
- 如果一个函数过长,不得不加上若干注释才能让这个函数显得易读一些,那这些函数就很有必要进行重构
- 如果在函数中有一段代码可以被独立出来,那最好把这些代码放进另外一个独立的函数中,这是一种很常见的优化工作。
- 项目越大,必须拆分得越细,好维护(函数也是如此)
- 千万不要一个函数从奶奶家写到外婆家去了
这样做的好处主要有以下几点:
- 避免出现超大函数
- 独立出来的函数有助于代码复用
- 独立出来的函数更容易被覆写
- 独立出来的函数如果拥有一个良好的命名,它本身就起到了注释的作用
比如在一个负责取得用户信息的函数里面,还需要打印跟用户信息有关的信息,那么打印的语句就可以被封装在一个独立的函数里:
let getUserInfo = function(){
ajax( 'http:// xxx.com/userInfo', function( data ){
console.log( 'userId: ' + data.userId );
console.log( 'userName: ' + data.userName );
console.log( 'nickName: ' + data.nickName );
});
};
//改成:
let getUserInfo = function(){
ajax( 'http:// xxx.com/userInfo', function( data ){
printDetails( data );
});
};
let printDetails = function( data ){
console.log( 'userId: ' + data.userId );
console.log( 'userName: ' + data.userName );
console.log( 'nickName: ' + data.nickName );
};
5.2 尽量减少参数
- 调用一个函数时需要传入多个参数,那这个函数是让人望而生畏的(甚至调用起来还会骂娘~)
- 必须搞清楚这些参数代表的含义,必须小心翼翼地把它们按照顺序传入该函数。
- 在实际开发中,向函数传递参数不可避免,但应该尽量减少函数接收的参数数量
比如我们需要封装一个CSS操作库:
- 第一版的代码
function cssTransform(ele, attr, val){
// ele 要操作的元素
// attr 运动属性 缩放,旋转
// val 具体值
if(!ele.transform){
ele.transform = {};
}
if(typeof val === "undefined"){
// 取值阶段
// 取不到 设置默认值
if(typeof ele.transform[attr] === "undefined"){
switch(attr){
case "scale":
case "scaleX":
case "scaleY":
case "scaleZ":
// attr是scale 默认值是1 其它都是0
ele.transform[attr] = 1;
break;
default:
ele.transform[attr] = 0;
}
}
// 取值完毕 返回该值
return ele.transform[attr];
}else{
// 赋值阶段
ele.transform[attr] = val; // 设置属性 方便取值
let transformVal = "";
for(var s in ele.transform){
switch(s){
case "scale":
case "scaleX":
case "scaleY":
case "scaleZ":
transformVal += " " + s + "("+(ele.transform[s])+")";
break;
case "rotate":
case "rotateX":
case "rotateY":
case "rotateZ":
case "skewX":
case "skewY":
transformVal += " " + s + "("+(ele.transform[s])+"deg)";
break;
default:
transformVal += " " + s + "("+(ele.transform[s])+"px)";
}
ele.style.WebkitTransform = ele.style.transform = transformVal;
}
}
}
- 我们需要传入三个参数,这就导致了传参的复杂性
- 可以将它绑定到HTML元素上,减少传参
HTMLElement.prototype.cssTransform = function (prop, value){
var transform,
transformValue = "";
if(this.transform === undefined) {
this.transform = transform = Object.create(null);
}
if(value !== undefined){
// 赋值阶段
this.transform[prop] = value;
transform = this.transform;
for(var name in transform){
switch(name){
case "scale":
case "scaleX":
case "scaleY":
case "scaleZ":
transformValue += " " + name + "("+ transform[name]+")";
break;
case "rotate":
case "rotateX":
case "rotateY":
case "rotateZ":
case "skewX":
case "skewY":
transformValue += " " + name + "("+ transform[name] + "deg)";
break;
default:
transformValue += " " + name + "("+ transform[name] + "px)";
}
this.style.WebkitTransform = this.style.transform = transformValue;
}
}else{
// 取值
return this.transform[prop];
}
}
- 现在就只需要两个参数了
- 核心代码没变,事件直接绑定在元素上,每一个html都拥有这个原型方法
- 调用更加方便,传参更加简单
6.条件优化
6.1 合并条件判断
- 如果一个函数体内有一些条件分支语句,而这些条件分支语句内部散布了一些重复的代码,那么就有必要进行合并去重工作。
- 假如有一个分页函数paging(),该函数接收一个参数currPage,currPage表示即将跳转的页码。
- 在跳转之前,为防止currPage传入过小或者过大的数字,要手动对它的值进行修正,详见如下代码
let paging = function( currPage ){
if ( currPage == 0 ){
currPage = 0;
jump( currPage ); // 跳转
}else if ( currPage == totalPage ){
currPage = totalPage;
jump( currPage ); // 跳转
}else{
jump( currPage ); // 跳转
}
};
- 可以看到,负责跳转的代码jump(currPage)在每个条件分支内都出现了,所以完全可以把这句代码独立出来
let paging = function( currPage ){
if ( currPage == 0 ){
currPage = 0;
}else if ( currPage == totalPage ){
currPage = totalPage;
}
jump( currPage ); // 把jump 函数独立出来
};
6.2 条件语句过多,提炼成函数
- 在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数
- 假设现在有一个需求是编写一个计算商品价格的 getPrice(),商品的计算只有一个规则:如果当前正处于夏季,那么所有冬装将以5折出售
let getPrice = function( price ){
let date = new Date();
if ( date.getMonth() > 6 && date.getMonth() < 10 ){ // 冬天
return price \* 0.5;
}
return price;
};
- 判断是否处于夏季
总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家
- 在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数
- 假设现在有一个需求是编写一个计算商品价格的 getPrice(),商品的计算只有一个规则:如果当前正处于夏季,那么所有冬装将以5折出售
let getPrice = function( price ){
let date = new Date();
if ( date.getMonth() > 6 && date.getMonth() < 10 ){ // 冬天
return price \* 0.5;
}
return price;
};
- 判断是否处于夏季
总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家
[外链图片转存中…(img-kyfuv0YF-1720101406879)]
[外链图片转存中…(img-b567RUx6-1720101406880)]