乐趣区

关于前端:你中了几条5个js编码的坏习惯

更多文章,请关注微信公众号: 前端 css 和 js 干货

在浏览 js 代码时,是否有过这样的感触:

  • 你简直不明确代码的意思?
  • 代码应用了很多过期的 JavaScript 技巧?
  • 命名和编码格调比拟随便?
    这些是编码不良习惯的迹象。

本文列举了 JavaScript 中 5 个常见的不良编码习惯。更重要的是,本文给出了如何改掉这些习惯的可行倡议。

1. 不要应用隐式类型转换

JavaScript 是一种弱类型的语言。如果应用切当,这是长处,因为它提供了灵活性。
大多数运算符 + – * / ==(不包含 ===)在解决不同类型的数据时应用隐式类型转换。
if (condition) {…}, while(condition) {…} 语句隐式地将条件转换为布尔值。
以下示例依赖于隐式类型转换。我打赌你会感到困惑:

console.log("2" + "1"); // => "21"

console.log("2" - "1"); // => 1

console.log('' == 0); // => true

console.log(true == []); // -> false

console.log(true == ![]); // -> false

适度依赖隐式类型转换是一个坏习惯。首先,它使你的代码在某些状况下不太稳固。其次,这使得难以复现也难以修复的 bug 变得更多。

上面是一个获取对象属性的函数。如果该属性不存在,该函数返回一个默认值:

function getProp(object, propertyName, defaultValue) {if (!object[propertyName]) {return defaultValue;}

return object[propertyName];

}

const hero = {

    name: 'Batman',

    isVillian: false

};

console.log(getProp(hero, 'name', 'Unknown')); // => 'Batman'

getProp() 读取 name 属性的值,即“Batman”。

如果拜访 isVillian 属性会产生什么:

console.log(getProp(hero, 'isVillian', true)); // => true

这是一个谬误。即便 hero 的 isVillian 属性为 false,函数 getProp() 也会返回谬误的 true。
这是因为属性是否存在判断,依赖于通过 if (!object[propertyName]) {…} 隐式转换为布尔值。这类谬误很难发现。要修复该函数,须要明确数据的类型。

function getPropFixed(object, propertyName, defaultValue) {if (object[propertyName] === undefined) {return defaultValue;}

return object[propertyName];

}

const hero = {

    name: 'Batman',

    isVillian: false

};

console.log(getPropFixed(hero, 'isVillian', true)); // => false

object[propertyName] === undefined 验证属性拜访器的运算后果是否为 undefined。
旁注:第 4. 节倡议防止间接应用 undefined。因而能够应用 in 运算符改良上述计划:

function getPropFixedBetter(object, propertyName, defaultValue) {if (!(propertyName in object)) {return defaultValue;}

    return object[propertyName];

}

倡议:尽可能不要应用隐式类型转换。相同,请确保变量和函数参数始终具备雷同的类型。必要时应用显式类型转换。

最佳实际列表:

  • 始终应用严格相等运算符 === 来执行比拟
  • 不要应用涣散相等运算符 ==
  • 加法运算符 operand1+operand2:两个操作数都应该是数字或都是字符串
  • 算术运算符 – * / %:两个操作数都应该是数字
  • if (condition) {…}, while (condition) {…} 等语句:condition 应该是一个布尔值
  • 你可能会说这种办法须要编写更多代码……的确是这样!然而通过明确的办法,你能够控制代码的行为。另外,这也减少了可读性。

2. 不要应用过期的 JavaScript 技巧

JavaScript 的乏味之处在于,它的创始人并没有预料到这种语言会变得如此风行。

基于 JavaScript 构建的应用程序的复杂性增长速度超过了语言的倒退速度。这种状况迫使开发人员应用 javaScript hacks 来实现性能。

一个经典的例子是搜寻一个数组是否蕴含一个元素。应用 array.indexOf(item) !== - 1 来监测元素是否存在。
ECMAScript 2015 及更高版本的性能变得越来越弱小。你能够应用新的语言个性平安地重构很多 hacks。

应用 ES2015 办法 array.includes(item) 重构 array.indexOf(item) !== -1。

3. 不要净化函数作用域

在 ES2015 之前,js 变量是函数作用域的,因而,你可能养成了以函数作用域的形式申明所有变量的坏习惯,请看一个例子:


function someFunc(array) {

    var index, item, length = array.length;

    /*

    * Lots of code

    */

    for (index = 0; index < length; index++) {item = array[index];

        // Use `item`

    }

    return someResult;

}

变量 index、item 和 length 是函数作用域的。然而这些变量会净化函数作用域,因为它们只在 for() 块作用域内是必须的。

随着块作用域变量申明关键字 let 和 const 的引入,咱们应该尽可能地限度变量的生命周期。

让咱们修改上述代码:

function someFunc(array) {

    /*

    * Lots of code

    */

    const length = array.length;

    for (let index = 0; index < length; index++) {const item = array[index];

        // Use `item`

    }

    return someResult;

}

index 和 item 变量仅存在于 for() 循环块范畴。length 挪动到其应用点的左近。
重构后的代码更容易了解,因为变量没有扩散在整个函数范畴内。它们存在于应用点左近。

在它们应用的块作用域内定义变量:
if 块作用域

// 不好的做法
let message;
// ...
if (notFound) {
  message = 'Item not found';
  // Use `message`
}
// 好的做法
if (notFound) {
  const message = 'Item not found';
  // Use `message`
}

for 块作用域

// 不好的做法
let item;
for (item of array) {// Use `item`}
// 好的做法
for (const item of array) {// Use `item`}

4. 尽量避免 undefined 和 null

尚未赋值的变量被主动评估为 undefined。例如:

let count;

console.log(count); // => undefined

const hero = {name: 'Batman'};

console.log(hero.city); // => undefined

count 变量已定义,但尚未用值初始化。JavaScript 隐式调配给它 undefined。
拜访不存在的属性 hero.city 时,也会返回 undefined。
为什么间接应用 undefined 是一个坏习惯?因为当咱们与 undefined 间接进行比拟时,咱们就有可能是在解决状态为未初始化的变量。
变量、对象属性、数组在应用之前必须用值初始化!
JavaScript 提供了很多办法来防止与 undefine 间接进行比拟。

属性是否存在:

// 不好的做法
const object = {prop: 'value'};
if (object.nonExistingProp === undefined) {// ...}

// 好的做法
const object = {prop: 'value'};
if ('nonExistingProp' in object) {// ...}

对象默认属性

// 不好的做法
function foo(options) {if (object.optionalProp1 === undefined) {object.optionalProp1 = 'Default value 1';}
  // ...
}

// 好的做法
function foo(options) {
  const defaultProps = {optionalProp1: 'Default value 1'};
  options = {
    ...defaultProps,
    ...options
  };
  // ...
}

函数默认参数

// 不好的做法
function foo(param1, param2) {if (param2 === undefined) {param2 = 'Some default value';}
  // ...
}


// 好的做法
function foo(param1, param2 = 'Some default value') {// ...}

你应该致力防止从函数中返回 null,更要防止应用 null 作为参数调用函数。
一旦 null 呈现在你的调用堆栈中,你就必须在每个可能拜访 null 的函数中查看变量是否为 null。这很麻烦也很容易出错,如下代码:

function bar(something) {if (something) {return foo({ value: 'Some value'});

    } else {return foo(null);

    }

}

function foo(options) {

    let value = null;

    if (options !== null) {

        value = options.value;

        // ...

    }

    return value;

}

尽量编写不波及 null 值的代码。一个代替计划是 try/catch 机制。
ALGOL 的发明者 Tony Hoare 曾说过:

我称其为我的十亿美元谬误 … 我正在为面向对象语言中的援用设计第一个综合类型零碎。但我无奈抗拒 null 援用的引诱,仅仅因为它很容易实现。这导致了有数谬误、破绽和零碎解体,在过来的四十年里,这些问题可能造成了 10 亿美元的苦楚和损失。

“计算机科学最重大的谬误”一文深入探讨了为什么 null 会侵害代码品质。

5. 不要应用随便的编码格调

有什么比浏览具备随机编码格调的代码更令人生畏的呢?你永远不晓得会产生什么!
如果代码库蕴含许多开发人员的不同编码格调怎么办?各式各样的人物涂鸦墙。

要求整个团队和利用程序代码库采纳雷同的编码格调。它进步了代码的可读性。

可参考的编码格调示例:

  • Airbnb JavaScript 格调指南
  • 谷歌 JavaScript 格调指南

倡议自动化验证代码格调:

  • 装置 eslint
  • 应用最适宜你的编码格调配置 eslint
  • 设置一个预提交钩子,在提交之前运行 eslint 验证。

6. 总结

编写高质量和洁净的代码须要纪律越是,克服不良的编码习惯。
JavaScript 是一种弱类型语言,有很大的灵活性。然而你必须分明本人所应用的个性。倡议是防止隐式类型转换并缩小 undefined 和 null 的应用。
最近几年 js 语言倒退得十分快。找到辣手的代码,并应用最新的 JavaScript 个性重构它。
代码库中统一的编码格调有利于可读性。
你还晓得 JavaScript 中还有哪些不好的编码习惯?

作者:dmitripavlutin 译者:前端 css 和 js 干货 起源:Dmitri Pavlutin

退出移动版