JavaScript 是对初学者比较友好的一门编程语言,基本上花个半小时看下语法就能写出能运行的代码。JavaScript 是动态脚本语言,对数据类型没有太多的限制,写起来非常灵活。但正因为如此,初学者如果不深入了解语言本身,往往会犯一些错误,从而导致一些很难发现的 bug。

抛开 JavaScript 语言设计层面的问题不说,毕竟它是 Brendan Eich 当年用短短十天时间设计出来的,有点缺陷也是在所难免。作为开发者,我们该怎样避免一些常见的低级错误呢?本文就列举几个常见错误,看看你有没有似曾相识。

混淆 undefined 和 null

JavaScript 中的undefined 和 null 都可用来表示没有值,但是二者之间有所区别。undefined字面意思是“未定义”,但它的含义其实已经超出了变量未定义的范畴:尝试读取对象不存在的属性、没有return语句的函数的返回值、声明后没有赋值的变量甚至显式赋值为undefined的变量等,它们的结果都是undefined。用typeof测试它的类型,是字符串 'undefined'。而 null 就比较纯粹了,变量只有设置为null 才有这个值。另外,null 是对象类型,即typeof(null)的值是字符串'object'

需要注意的是,用if判断这两个值都是false,而且null==undefined是成立的,这一点初学者通常容易搞混。因此,尽量统一把“没有值”都设置为undefined,这样就省去了判断区分的麻烦。

返回 undefined的函数:

const f = () => {}

设置变量的值为 undefined

x = undefined;

判断属性是否为 undefined

typeof obj.prop === 'undefined'
obj.prop === undefined

判断变量是否为 undefined

typeof x === 'undefined'

变量声明后没有赋值,自动就有了 undefined值。

如果一定要判断null,用全等判断:

obj.prop === null
x === null

使用 typeof 是无法判断 null的,因为它是对象类型。

混淆数字相加和字符串拼接

在 JavaScript 中,加号 +操作符既可用于数字相加,也可以用于字符串拼接。由于 JavaScript 是动态语言,操作符会自动将变量转成相同数据类型再运算。比如:

let x = 1 + 1; // 2

结果是 2,是我们期望的数字相加操作,因为两个值都是数字。

但是,如果是下面这种表达式:

let x = 1 + '1'; // “11”

结果是'11',因为第一个数字会转换成字符串。这里的加号+运算符被用作字符串拼接,而不是数字相加。这里能直接看到表达式的值还算清楚,如果是由多个变量组成的表达式就很难判断类型了。

为了解决这个问题,我们可以把字符串都转成数字类型,再进行运算。例如:

let x = 1;
let y = '2';
let z = Number(x) + Number(y);

这样,运行结果就是3了。 Number函数接收任意类型的值,如果能转成数字就返回数字,否则返回NaN。还可以用 new Number(...).valueOf()函数:

let x = 1;
let y = '2';
let z = new Number(x).valueOf() + new Number(y).valueOf();

由于 new Number(...) 是实例化一个构造函数,返回的是一个对象,并不是数字类型。如果要得到原始的数字类型,需要用该对象的valueOf方法。其实还有个更简洁的方法:

let x = 1;
let y = '2';
let z = +x + +y;

变量前面的 + 作用是将它转换成数字,或者NaN ,跟Number函数的作用相同。

return 语句换行问题

JavaScript 语法规定换行代表语句结束。例如:

const add = (a, b) => {
return
a + b;
}
add(1,2); // undefined

本以为会返回 3,实际上是undefined。这是因为在a + b之前,函数已经执行了return。要解决这个问题,有两个做法:要么把表达式跟return放在一行,要么把表达式套一层括号。

const add = (a, b) => {
return a + b;
}
// 或者
const add = (a, b) => {
return (
a + b
);
}

加括号为什么可以换行呢?因为括号里的是表达式,不是语句。表达式可以拆成多行,如果很长的话。用箭头函数会更直观:

const add = (a, b) => a + b

箭头函数里的单行表达式自带return效果,当然也可以在表达式外面套一层括号:

const add = (a, b) => (a + b)

这个括号在返回对象字面量的箭头函数里有点用处,因为不加圆括号()的话,{}只是函数体的开始和结束标记,要返回对象字面量,还要显式return {...}

如果某行代码中的语句不完整,JavaScript 解析器会将下一行的语句合并一起解析。比如:

const power = (a) => {
const
power = 10;
return a ** 10;
}
// 等同于:
const power = (a) => {
const power = 10;
return a ** 10;
}

但是对于完整的语句,比如return,就不会合并多行。

用 return 跳出 forEach 循环

JavaScript 数组有个 forEach 方法,用于对数组元素进行循环操作。初学者很容易联想到 for循环的breakcontinue关键字,用来中止循环。但是对不起,forEach没有这两个关键字。那用return行不行?可以用,但它的作用就是提前返回函数,跟continue的效果类似,用于结束本次循环。要跳出整个循环,return做不到。

const nums = [1, 2, 3, 4, 5, 6];
let firstEven;
nums.forEach(n => {
if (n % 2 ===0 ) {
firstEven = n;
return n;
}
});
console.log(firstEven); // 6

代码本意是想找出第一个偶数,找到就退出循环。但实际并没有退出循环,因此最终结果是最后一个偶数。

有解决办法吗?这种情况可以用for循环,或者用数组filterfind之类的方法。

总结

虽然 JavaScript 很容易上手,但稍不注意还是比较容易犯错。本文简单介绍了几种容易犯的错,希望对你有所帮助。

更多前端技术干货尽在微信公众号:1024译站

JavaScript 初学者容易犯的几个错误,你中招没?的更多相关文章

  1. python3 之初学者常犯的5个错误

    1. Creating a copy of dictionary or lists. Whenever you need to make a copy of a dictionary or list, ...

  2. javascript中易犯的错误有哪些

    javascript中易犯的错误有哪些 一.总结 一句话总结: 比如循环中函数的使用 函数中this的指向谁(函数中this的使用) 变量的作用域 1.this.timer = setTimeout( ...

  3. javaScript初学者易错点

    大家好,这是我在博客园写的第一篇博文.作为一名前端开发初学者,由于经验不足,水平有限,在做项目的过程中总会遇到这样或那样的问题,每每这时候,我都比较喜欢到博客园这里来寻求解决方案,结果也总是能找到满意 ...

  4. JavaScript 初学者应知的 24 条最佳实践

    原文:24 JavaScript Best Practices for Beginners (注:阅读原文的时候没有注意发布日期,觉得不错就翻译了,翻译到 JSON.parse 那一节觉得有点不对路才 ...

  5. 给JavaScript初学者的24条最佳实践

    ­.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0 } .fluid-width-video-wrapp ...

  6. 给JavaScript初学者的24条最佳实践(share)

    不错的文章,留个备份 原文链接: net.tutsplus   翻译: 伯乐在线- yanhaijing译文链接: http://blog.jobbole.com/53199/ 作为“30 HTML和 ...

  7. Web开发人员常犯的10个错误

    说到开发一个运行在现代网络中的网站:Web开发人员需要选择虚拟主机平台和底层数据存储,准备编写HTML.CSS和JavaScript用的工具,要有设计执行方式,以及一些可用的JavaScript库/框 ...

  8. 给JavaScript初学者的24条最佳实践(转:http://www.cnblogs.com/yanhaijing/p/3465237.html)

    作为“30 HTML和CSS最佳实践”的后续,本周,我们将回顾JavaScript的知识 !如果你看完了下面的内容,请务必让我们知道你掌握的小技巧! 1.使用 === 代替 == JavaScript ...

  9. 转载----给JavaScript初学者的24条最佳实践

      给JavaScript初学者的24条最佳实践 1.使用 === 代替 == JavaScript 使用2种不同的等值运算符:===|!== 和 ==|!=,在比较操作中使用前者是最佳实践. “如果 ...

随机推荐

  1. Go网络编程

    概述 网络协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则.假设,A.B双方欲传输文件.规定: 第一次,传输文件名,接收方接收到文件名,应答OK给传输方: ...

  2. k8s(1.14.0)+etcd(3.3.10)+flanneld(0.10)

    K8s(1.14) 几张比较不错的图 1.kubernetes 组件图 kubernetes 架构图 2.kubernetes 网络架构图 数据从源容器中发出后,经由所在主机的docker0虚拟网卡转 ...

  3. 常见的sql注入环境搭建

    常见的sql注入环境搭建 By : Mirror王宇阳 Time:2020-01-06 PHP+MySQL摘要 $conn = new mysqli('数据库服务器','username','pass ...

  4. angular.foreach 循环方法

    angular循环给一个 angular监听的变量复值时.最好还是用angular自带的循环方法.“angular.foreach” 尽量避免代码的冲突,最好不要jq angular 混用 var o ...

  5. Java扫描指定文件路径下的文件并且递归扫描其子目录下的所有文件

    本文主要实现了扫描指定文件路径下的文件,递归扫描其子目录下的所有文件信息,示例文件为: 要求将后缀为.dat的文件夹信息也写入到数据库中,然后将.chk文件解析,将文件中对应的内容读出来写入到数据库, ...

  6. C#调用Fortran生成的DLL的方法报内存不足

    最近在研究一个程序,公司给的,程序是VB写的,程序里面还有一个计算的模型,用Fortran语言写的. 在调试到这个模型里面的方法时报错,说是内存不足,于是就在网上查找方法,看了两篇博客之后问题解决了. ...

  7. mongodb学习(二)——基本的数据操作

    数据操作(重点) 数据库的核心--CRUD,增加和删除较为简单,查询和修改较复杂 查询 关系运算符 $gt 大于 $lt 小于 $gte 大于等于 $lte 小于等于 $eq | (key: valu ...

  8. python——pickle模块的详解

    pickle模块详解 该pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议. “Pickling”是将Python对象层次结构转换为字节流的过程, “unpickling”是反 ...

  9. Spring Boot2 系列教程 (七) | 使用 Spring Data JPA 访问 Mysql

    前言 如题,今天介绍 Spring Data JPA 的使用. 什么是 Spring Data JPA 在介绍 Spring Data JPA 之前,首先介绍 Hibernate . Hibernat ...

  10. Adaboost和随机森林

    在集成学习中,主要分为bagging算法和boosting算法.随机森林属于集成学习(Ensemble Learning)中的bagging算法. Bagging和Boosting的概念与区别该部分主 ...