第十四期:5 个 JS 不良编码习惯,你占几个呢?

在阅读JavaScript代码时,你是否有过这种感觉:你几乎不明白代码的作用?代码使用了很多 JavaScript 技巧?命名和编码风格太过随意? 这些都是不良编码习惯的征兆。

 

在阅读JavaScript代码时,你是否有过这种感觉

  • 你几乎不明白代码的作用?
  • 代码使用了很多 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。

这里建议避免直接使用undefined。 因此,上述解决方案可以进一步改进:

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技巧和变通方法,只是为了让事情正常运行。

一个典型的例子是查看数组是否包含某个元素。 我从来不喜欢使用array.indexOf(item)!== -1来检查。

ES6 及以后版本的功能要强大得多,可以使用新的语言特性安全地重构许多技巧。

ES6 中可以使用 array.includes(item) 来代替 array.indexOf(item) !== -1

3. 不要污染函数作用域

在ES2015之前,你可能会养成了将所有变量声明在函数作用域里面。

来看看一个例子:

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进行比较时,你正在处理未初始化状态的变量。

变量、对象属性和数组在使用前必须用值初始化

JS 提供了很多避免与undefined进行比较方式。

判断属性是否存在

// 不好 
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机制,默认对象的使用。

5. 不要使用随意的编码风格,执行一个标准

有什么比阅读具有随机编码风格的代码更令人生畏的事情? 你永远不知道会发生什么!

如果代码库包含许多开发人员的不同编码风格,该怎么办?,这种就像各色人物涂鸦墙。

整个团队和应用程序代码库都需要相同的编码风格,它提高了代码的可读性。

一些有用的编码风格的例子:

  • Airbnb JS 风格指南
  • 谷歌 JS 风格指南

老实说,当我在回家前准备提交时,我可能会忘记设计代码的样式。

我自己总说:保持代码不变,以后再更新它,但是“以后”意味着永远不会。

这里建议使用 eslint 来规范编码风格。

  1. 安装eslint
  2. 使用最适合自己的编码风格配置 eslint
  3. 设置一个预提交钩子,在提交之前运行eslint验证。

总结

编写高质量和干净的代码需要纪律,克服不好的编码习惯。

JavaScript是一种宽容的语言,具有很大的灵活性。但是你必须注意你所使用的特性。这里建议是避免使用隐式类型转换,undefined 和 null 。

现在这种语言发展得相当快。找出复杂的代码,并使用最新 JS 特性来重构。

整个代码库的一致编码风格有益于可读性。良好的编程技能总是一个双赢的解决方案。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。


阅读目录(置顶)(长期更新计算机领域知识)https://blog.csdn.net/weixin_43392489/article/details/102380691

阅读目录(置顶)(长期更新计算机领域知识)https://blog.csdn.net/weixin_43392489/article/details/102380882

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣3. 无重复字符的最长子串 two pointer算法|滑动窗口|尺取法

无重复字符的最长子串 给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最…

318. Maximum Product of Word Lengths

问题&#xff1a;给定一个字符串数组words&#xff0c;找到这样的最大值&#xff1a;length(word[i]) * length(word[j])&#xff0c;words[i]和words[j]没有共同的字母。假设输入字符串只包含小写字母。如果不存在这样的两个字符串&#xff0c;则返回0。 思路&#xff1a;难点…

第十五期:详解Java集合框架,让你全面掌握!

一、Java集合框架概述 集合可以看作是一种容器&#xff0c;用来存储对象信息。所有集合类都位于java.util包下&#xff0c;但支持多线程的集合类位于java.util.concurrent包下。 数组与集合的区别如下&#xff1a; 1&#xff09;数组长度不可变化而且无法保存具有映射关系的…

[Leetcode][第98 450 700 701题][JAVA][二叉搜索树的合法性、增、删、查][递归][深度遍历]

【二叉搜索树定义】&#xff08;BST&#xff09; 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称 BST&#xff09;是一种很常用的的二叉树。它的定义是&#xff1a;一个二叉树中&#xff0c;任意节点的值要大于等于左子树所有节点的值&#xff0c;且要小于等于右边…

关于CNN的权重共享,CNN到底学到了什么?

CNN的fliter里的每个值都是学习出来的不是事先设定好的。 经过fliter处理后得到是特征图(feature map) 卷积减少权重参数的本质&#xff1a; 权重共享&#xff0c;不同的fliter会在某些神经元上权重共享。 到底fliter&#xff0c;到底CNN学到了什么&#xff1f; 底层的flite…

复盘二进制的习题(1)

本文是对近期二进制专题的leetcde习题的复盘。文中的解决思路来源于leetcode的讨论&#xff0c;以及一些网页。 342 判断一个整数(32bits)是否是4的次幂。  写出4i,i0,1,2,3,4...的二进制表示&#xff0c;查找规律。会发现这些数的特征是 a 都>0&#xff1b;b 只有一位是…

第十六期:简单的介绍一下大数据中最重要的MapReduce

MapReduce是分布式运行的&#xff0c;由两个阶段组成&#xff1a;Map和Reduce&#xff0c;Map阶段是一个独立的程序&#xff0c;有很多个节点同时运行&#xff0c;每个节点处理一部分数据。 MapReduce执行流程图 概述 MapReduce是一种分布式计算模型&#xff0c;由Google提出…

【perl】simpleHTTP

【perl】simpleHTTP 类似Python SimpleHTTPServer #!/usr/bin/perl # https://metacpan.org/pod/HTTP::Server::Simple # https://metacpan.org/pod/distribution/CGI/lib/CGI.pod package WebServer;use strict; use warnings FATAL > all; use HTTP::Server::Simple::CGI;…

【数据结构与算法】快排、归并 O(nlogn) 基于比较

冒泡、插入、选择 O(n^2) 基于比较 快排、归并 O(nlogn) 基于比较 计数、基数、桶 O(n) 不基于比较 一、分治思想 1.分治思想&#xff1a;分治&#xff0c;顾明思意&#xff0c;就是分而治之&#xff0c;将一个大问题分解成小的子问题来解决&#xff0c;小的子问题解决了&…

第四章切比雪夫不等式、大数定理、中心极限定理

切比雪夫不等式 设随机变量X具有数学期望E(X)μ&#xff0c;方差D(X)σ2&#xff0c;对于任意ε>0&#xff0c;都有P{|X−μ|≥ε}≤σ2ε2方差越大&#xff0c;X落在区间外的概率越大&#xff0c;X的波动也就越大&#xff0c;与方差的意义统一了。等价公式P{|X−μ|<ε}…

第十七期:记一次生产环境SQL Server服务器卡顿问题解决--内存分配不当

概述 最近有台数据库做了迁移&#xff0c;然后运维人员过了一段时间发现这台服务器非常卡&#xff0c;连远程登录都要很久&#xff0c;下面记录下其中的解决过程。 1、查看资源情况 可以发现内存爆满了&#xff0c;而排名第一的正是sqlserver的进程 2、查看sqlserver内存分配…

Python的dnspython库使用指南

因为平时在测试DNS的时候有些操作手动完成不方便&#xff0c;所以需要用到脚本&#xff0c;而在Python里dnspython这个用于DNS操作的库十分强大&#xff0c;但是无奈网上大部分资料只列举了少部分的用法&#xff0c;所以记录一下我平时使用到的功能&#xff0c;基本上已经能应付…

leetcode 42 接雨水 单调栈

接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图&#xff0c;在这种情况下&#xff0c;可以接 6 个单位的雨水&#xff08;蓝色部分表示雨水…

第十八期:网页禁止复制粘贴怎么办?教你六招轻松搞定

经常在网上遇到一些无法复制的文章&#xff0c;那么问题来了&#xff0c;有什么办法可以绕开这种限制&#xff0c;将网页内容轻松下载回来呢&#xff1f; 经常在网上遇到一些无法复制的文章&#xff0c;那么问题来了&#xff0c;有什么办法可以绕开这种限制&#xff0c;将网页内…

[Leetcode][第99题][JAVA][恢复二叉搜索树][中序遍历]

【问题描述】[困难] 【解答思路】 1. 显示中序遍历 时间复杂度&#xff1a;O(N) 空间复杂度&#xff1a;O(N) class Solution {public void recoverTree(TreeNode root) {List<Integer> nums new ArrayList<Integer>();inorder(root, nums);int[] swapped find…

复盘二进制的习题(2)

338 Counting Bits。输入一个整数n&#xff0c;对于 0 ≤ i ≤ num&#xff0c;计算每个数的二进制1的个数。例如&#xff1a;num 5 返回 [0,1,1,2,1,2]。希望能在O(n)的时间内完成。这里有动态规划的思想。 思路一&#xff1a; 十进制数二进制表示0000010011(0的bits)20101…

c#XML的基本使用

创建XML文档 static void Main(string[] args){//1.引入命名空间//2.创建XML文档对象XmlDocument xmldoc new XmlDocument();//3.创建第一行描述信息&#xff0c;添加到xmldoc文档中XmlDeclaration xmldec xmldoc.CreateXmlDeclaration("1.0", "utf-8", …

第四十一期:深度解析5G核心网建设难点和挑战

目前核心网处于架构转型和业务转型的关键期。在架构层面&#xff0c;NFV、CU分离、边缘计算等技术的成熟推动核心网络架构转型&#xff0c;控制面进一步集中&#xff0c;转发面进一步下沉。 目前核心网处于架构转型和业务转型的关键期。在架构层面&#xff0c;NFV、CU分离、边缘…

linux 进入一个中文乱码的目录的方法

bash命令&#xff1a;cd ls | awk NRxxx awk命令&#xff1a;获取第xxx行的目录名称&#xff0c;加上NR表示从第一行开始读的行号取 NR已经读出的记录数&#xff0c;就是行号&#xff0c;从1开始 用|把ls的结果传给后面的awk命令&#xff0c;连接上前面的cd就能进入啦 导引号…

[Leetcode][第696题][JAVA][计算二进制子串][分组]

【问题描述】[简单] 【解答思路】 1. 按字符分组 将字符串 ss 按照 00 和 11 的连续段分组&#xff0c;存在counts 数组中&#xff0c;例如 s 00111011&#xff0c;可以得到这样的counts 数组&#xff1a;counts{2,3,1,2}。 这里counts 数组中两个相邻的数一定代表的是两种…