您的位置:首页 > Web前端 > JavaScript

开发人员在JavaScript中犯的9个最常见错误(以及如何解决)

2020-08-19 23:55 351 查看

JavaScript is a scripting language used in webpages to add functionality and interactivity. For a beginner coming from a different programming language, JavaScript is quite easy to understand. With a few tutorials, you should be able to get started with it right away.

JavaScript是网页中用于添加功能和交互性的脚本语言 。 对于使用不同编程语言的初学者来说,JavaScript很容易理解。 通过一些教程,您应该可以立即开始使用它。

However, there are a few common mistakes that many beginner programmers make. In this article, we’ll address nine common mistakes (or bad practices) and their solutions to help you become a better JS developer.

但是,许多初学者会犯一些常见的错误。 在本文中,我们将解决9个常见错误(或不良做法)及其解决方案,以帮助您成为更好的JS开发人员。

混淆赋值(=)和相等(==,===)运算符 (Confusing the assignment (=) and equality (==, ===) operators)

Like its name implies, the assignment operator(=) is used to assign values to variables. Developers often confuse it with the equality operator.

顾名思义, 赋值运算符 (=)用于为变量赋值。 开发人员经常将其与相等运算符混淆。

Here's an example:

这是一个例子:

const name = "javascript";
if ((name = "nodejs")) {
console.log(name);
}
// output - nodejs

The name variable and ‘nodejs' string are not compared in this case. Instead, 'nodejs' is assigned to name and 'nodejs' is printed to the console.

在这种情况下,不比较名称变量和'nodejs'字符串。 相反,将“ nodejs”分配给名称,并将“ nodejs”打印到控制台。

In JavaScript, the double equal sign(==) and triple equal sign(===) are called comparison operators.

在JavaScript中,双等号(==)和三等号(===)称为比较运算符。

For the code above, this is the appropriate way of comparing values:

对于上面的代码,这是比较值的适当方法:

const name = "javascript";
if (name == "nodejs") {
console.log(name);
}
// no output
// OR
if (name === "nodejs") {
console.log(name);
}
// no output

The difference between these comparison operators is that the double equals performs a loose comparison while triple equals performs a strict comparison.

这些比较运算符之间的区别在于,double equals执行宽松的比较,而Triple equals执行严格的比较。

In a loose comparison, only the values are compared. But in a strict comparison, the values and datatype are compared.

在粗略的比较中,仅比较值。 但是在严格的比较中,将比较值和数据类型。

The following code explains it better:

以下代码对其进行了更好的解释:

const number = "1";
console.log(number == 1);
// true
console.log(number === 1);
// false

The variable number was assigned a string value of 1. When compared with 1 (of number type) using double equals, it returns true because both values are 1.

变量号的字符串值为1。与双精度等号的1(数字类型)比较时,它返回true,因为两个值均为1。

But when compared using triple equals, it returns false because each value has a different data type.

但是,当使用三元等于进行比较时,由于每个值具有不同的数据类型,因此它返回false。

期望回调是同步的 (Expecting callbacks to be synchronous)

Callbacks are one way that JavaScript handles asynchronous operations. Promises and async/await, however, are preferable methods for handling asynchronous operations because multiple callbacks lead to callback hell.

回调是JavaScript处理异步操作的一种方式。 但是,Promises和async / await是处理异步操作的首选方法,因为多个回调会导致回调hell

Callbacks are not synchronous. They are used as a function to be called after an operation when a delayed execution completes.

回调不是同步的 。 它们用作延迟执行完成后在操作后调用的函数。

An example is the global

setTimeout​
function which receives a callback function as its first argument and a duration (in ms) as a second argument like so:

一个例子是全球

setTimeout​
其接收回调函数作为像这样的第二参数的第一个参数和一个持续时间(毫秒)功能:

function callback() {
​​    console.log("I am the first");
​​}
​​setTimeout(callback, 300);
​​console.log("I am the last");
​​// output
​​// I am the last
​​// I am the first

After 300 milliseconds, the callback function is called. But before it completes, the rest of the code runs. This is the reason why the last console.log was run first.​​

300毫秒后,将调用回调函数。 但在完成之前,其余代码将运行。 这就是为什么最后一个console.log首先运行的原因。

A common mistake developers make is to misinterpret callbacks as synchronous. For example, a callback which returns a value that would be used for other operations.

开发人员常犯的一个错误是将回调误解为同步。 例如,一个回调返回一个将用于其他操作的值。

​​Here's that mistake:

这是一个错误:

function addTwoNumbers() {
​​    let firstNumber = 5;
​​    let secondNumber;
​​    setTimeout(function () {
​​        secondNumber = 10;
​​    }, 200);
​​    console.log(firstNumber + secondNumber);
​​}
​​addTwoNumbers();
​​// NaN

NaN
​ is the output because
secondNumber​
is undefined​. At the time of running
firstNumber + secondNumber
,
secondNumber
is still undefined because the
setTimeout
function would execute the callback after
200ms
.

NaN
是输出,因为
secondNumber​
不确定。 在运行
firstNumber + secondNumber
secondNumber
仍未定义,因为
setTimeout
函数将在
200ms
后执行回调。

The best way to approach this is to execute the rest of the code in the callback function:

解决此问题的最佳方法是执行回调函数中的其余代码:

function addTwoNumbers() {
​​    let firstNumber = 5;
​​    let secondNumber;
​​    setTimeout(function () {
​​        secondNumber = 10;
​​        console.log(firstNumber + secondNumber);
​​    }, 200);
​​}
​​addTwoNumbers();
​​// 15

到错误引用
this​
(Wrong references to
this​
)

this​
is a commonly misunderstood concept in JavaScript. To use
this
​ in JavaScript, you really need to understand how it works because it operates a bit differently compared to other languages.

this​
是一个常见的误解的概念在JavaScript中。 要在JavaScript中使用
this
,您真的需要了解它的工作原理,因为它的运行方式与其他语言相比有所不同。

Here's an example of a common mistake when using

this​
:

下面是在使用一个常见的错误的例子

this​

const obj = {
​​    name: "JavaScript",
​​    printName: function () {
​​        console.log(this.name);
​​    },
​​    printNameIn2Secs: function () {
​​        setTimeout(function () {
​​            console.log(this.name);
​​        }, 2000);
​​    },
​​};
​​obj.printName();
​​// JavaScript
​​obj.printNameIn2Secs();
​​// undefined

​​The first result is

JavaScript
because
this.name
​ correctly points to the object's name property. The second result is
undefined
because
this​
has lost reference to the object's properties (including name).

第一个结果是

JavaScript
因为
this.name
正确指向对象的name属性。 第二个结果是
undefined​
,因为
this​
已经失去参考对象的属性(包括名称)。

This is because

this​
depends on the object calling the function which it lives in. There is a
this
​ variable in every function but the object it points to is determined by the object calling it.

这是因为

this​
取决于调用它生活在该函数的对象。有一个
this
变量在每一个功能,但它指向的是通过调用它的对象决定的对象。

The

this​
in
obj.printName()
​ points directly to
obj
​. The
this
​ in
obj.printNameIn2Secs​
points directly to
obj​
. But the
this​
in the callback function of
setTimeout​
does not point to any object because no object called it.

this​
obj.printName()
直接指向
obj
。 在
this
obj.printNameIn2Secs​
直接指向
obj​
。 但是,
this​
在回调函数
setTimeout​
不指向任何对象,因为没有对象调用它。

For an object to have called

setTimeout​
, something like
obj.setTimeout...​
would be executed. Since there is no object calling that function, the default object (which is
window
​) is used.

对于一个对象,以呼吁

setTimeout​
,像
obj.setTimeout...​
会被处决。 由于没有对象调用该函数,因此使用默认对象(即
window
)。

​​

name
​ does not exist on window​, resulting in
undefined
​.

name
上不存在窗口,导致
undefined

The best ways to go about retaining the reference to

this
​ in
setTimeout
is to use
bind​
,
call​
,
apply
​ or arrow functions (introduced in ES6). Unlike normal functions, arrow functions do not create their own
this
​.

到去保留提及的最佳途径

this
setTimeout
是使用
bind​
call​
apply
或箭头功能(在ES6介绍)。 与普通函数不同,箭头函数不会创建自己的
this

​​So, the following will retain its reference to

this​
:​​

因此,下面将保留其参考

this​

​​const obj = {
​​    name: "JavaScript",
​​    printName: function () {
​​        console.log(this.name);
​​    },
​​    printNameIn2Secs: function () {
​​        setTimeout(() => {
​​            console.log(this.name);
​​        }, 2000);
​​    },
​​};
​​obj.printName();
​​// JavaScript
​​obj.printNameIn2Secs();
​​// JavaScript

忽略对象可变性 (Disregarding object mutability)

Unlike primitive data types like string, number and so on, in JavaScript objects are reference data types. For example, in key-value objects:

与字符串,数字等原始数据类型不同,JavaScript对象中的引用数据类型是。 例如,在键值对象中:

const obj1 = {
​​    name: "JavaScript",
​​};
​​const obj2 = obj1;
​​obj2.name = "programming";
​​console.log(obj1.name);
​​// programming

obj1​
and
obj2
​ possess the same reference to the location in memory where the object is stored.

obj1​
obj2
具有在存储器中的相同的参考位置,其中所述对象被存储。

In arrays:

在数组中:

const arr1 = [2, 3, 4];
​​const arr2 = arr1;
​​arr2[0] = "javascript";
​​console.log(arr1);
​​// ['javascript', 3, 4]

A common mistake developers make is they disregard this nature of JavaScript and this results in unexpected errors. For instance, if 5 objects have the same reference to the same object, one of the object may interfere with the properties in a large-scale code base.

开发人员经常犯的一个错误是他们无视JavaScript的这种特性,这会导致意外错误。 例如,如果5个对象对同一对象的引用相同,则其中一个对象可能会干扰大规模代码库中的属性。

When this happens, any attempt to access the original properties would return undefined​ or possibly throw an error.

发生这种情况时,任何访问原始属性的尝试都将返回未定义或可能引发错误。

The best practice for this is to always create new references for new objects when you want to duplicate an object. To do this, the rest operator (

...​
 introduced in ES6) is a perfect solution.

最佳做法是在要复制对象时始终为新对象创建新引用。 要做到这一点,其余的运营商(

...​
在ES6介绍)是一个完美的解决方案。

​​For example, in key-value objects:

例如,在键值对象中:

​​const obj1 = {
​​    name: "JavaScript",
​​};
​​const obj2 = { ...obj1 };
​​console.log(obj2);
​​// {name: 'JavaScript' }
​​obj2.name = "programming";
​​console.log(obj.name);
​​// 'JavaScript'

​​In arrays:

数组中:

const arr1 = [2, 3, 4];
​​const arr2 = [...arr1];
​​console.log(arr2);
​​// [2,3,4]
​​arr2[0] = "javascript";
​​console.log(arr1);
​​// [2, 3, 4]

将数组和对象保存到浏览器存储 (Saving arrays and objects to browser storage)

Sometimes, while working with JavaScript, developers may want to take advantage of the

localStorage
for saving values. But a common mistake is trying to save arrays and objects as-is in the
localStorage
.
localStorage
only accepts strings.

有时,在使用JavaScript时,开发人员可能想利用

localStorage
来保存值。 但是一个常见的错误是试图将数组和对象原样保存在
localStorage
localStorage
仅接受字符串。

In an attempt to save objects, JavaScript converts the object to a string. The result is

[Object Object]
for objects and a comma-separated string for array elements.

为了保存对象,JavaScript将对象转换为字符串。 结果是

[Object Object]
和数组元素的逗号分隔字符串。

For example:

例如:

​​const obj = { name: "JavaScript" };
​​window.localStorage.setItem("test-object", obj);
​​console.log(window.localStorage.getItem("test-object"));
​​// [Object Object]
​​const arr = ["JavaScript", "programming", 45];
​​window.localStorage.setItem("test-array", arr);
​​console.log(window.localStorage.getItem("test-array"));
​​// JavaScript, programming, 45

When objects are saved like this, it becomes difficult to access them. For the object example, accessing the object like

.name​
would result in an error. This is because
[Object Object]
is a string now, without a
​name
property.

这样保存对象时,将很难访问它们。 对于对象例如,访问对象等

.name​
将导致一个错误。 这是因为
[Object Object]
现在是一个字符串,没有
​name
属性。

A better way to save objects and arrays in local storage is by using

JSON.stringify​
(for converting objects to strings) and
JSON.parse​
(for converting strings to objects). This way, accessing the objects becomes easy.

一种更好的方式来保存在本地存储对象和数组是通过使用

JSON.stringify​
(对于对象转换为字符串)和
JSON.parse​
(用于将字符串转换为对象)。 这样,访问对象变得容易。

The correct version of the code above would be:

上面的代码的正确版本是:

​​const obj = { name: "JavaScript" };
​​window.localStorage.setItem("test-object", JSON.stringify(obj));
​​const objInStorage = window.localStorage.getItem("test-object");
​​console.log(JSON.parse(objInStorage));
​​// {name: 'JavaScript'}
​​const arr = ["JavaScript", "programming", 45];
​​window.localStorage.setItem("test-array", JSON.stringify(arr));
​​const arrInStorage = window.localStorage.getItem("test-array");
​​console.log(JSON.parse(arrInStorage));
​​// JavaScript, programming, 45

不使用默认值 (Not using default values)

Setting default values in dynamic variables is a very good practice for preventing unexpected errors. Here's an example of a common mistake:​​

在动态变量中设置默认值是防止意外错误的一种很好的做法。 这是一个常见错误的例子:

function addTwoNumbers(a, b) {
​​    console.log(a + b);
​​}
​​addTwoNumbers();
​​// NaN

The result is

NaN​
because
a
​ is
undefined
​ and
b
​ is
undefined​
. By using default values, errors like this can be prevented. For example:

其结果是

NaN​
,因为
a
undefined
b
undefined​
。 通过使用默认值,可以防止类似的错误。 例如:

function addTwoNumbers(a, b) {
​​    if (!a) a = 0;
​​    if (!b) b = 0;
​​    console.log(a + b);
​​}
​​addTwoNumbers();
​​// 0

Alternatively, the default value feature introduced in ES6 can be used like so:

另外,可以像这样使用ES6中引入的默认值功能:

​​function addTwoNumbers(a = 0, b = 0) {
​​    console.log(a + b);
​​}
​​addTwoNumbers();
​​// 0

This example, though minimal, emphasizes the importance of default values. Additionally, developers can provide errors or warning messages when expected values are not provided.

这个例子虽然很小,但强调了默认值的重要性。 此外,当未提供期望值时,开发人员可以提供错误或警告消息。

变量命名不正确 (Improper naming of variables)

Yes, developers still make this mistake. Naming is hard, but developers really have no choice. Comments are good practice in programming, and so is naming variables.

是的,开发人员仍然会犯此错误。 命名很困难,但是开发人员确实别无选择。 注释是编程的好习惯,命名变量也是如此。

For example:

例如:

function total(discount, p) {
​​    return p * discount
​​}

The variable

discount
​ is okay, but what about
p
​ or
total​
? Total of what? A better practice for above would be:

变量

discount
是好的,但对于
p
total​
? 总共是什么? 更好的做法是:

function totalPrice(discount, price) {
​​    return discount * price
​​}

​​Properly naming variables is important because a developer may never be the only developer on a codebase at a particular time or in the future.

正确命名变量很重要,因为在特定的时间或将来,开发人员可能永远不是代码库中唯一的开发人员。

Naming variables properly will allow contributors easily understand how a project works.

正确命名变量将使贡献者可以轻松地了解项目的工作方式。

检查布尔值 (Check-up for boolean values)

const isRaining = false
​​if(isRaining) {
​​    console.log('It is raining')
​​} else {
​​    console.log('It is not raining')
​​}
​​// It is not raining

It is common practice to check boolean values as seen in the above code. While this is okay, errors set in when testing some values.

如上面的代码所示,检查布尔值是一种常见的做法。 虽然可以,但是在测试某些值时会设置错误。

​​In JavaScript, a loose comparison of

0
​ and
false
​ returns
true
and
1
​ and
true​
returns
true
. This means that if
isRaining
​ was
1
​,
isRaining
​ would be
true
.

在JavaScript中,一个松散的比较

0
false
返回
true
1
true​
返回
true
。 这意味着如果
isRaining
1
,则
isRaining
true

This is also a mistake often made in objects. For example:

这也是对象经常犯的错误。 例如:

const obj = {
​​    name: 'JavaScript',
​​    number: 0
​​}
​​if(obj.number) {
​​    console.log('number property exists')
​​} else {
​​    console.log('number property does not exist')
​​}
​​// number property does not exist

Although the

number
​ property exists,
obj.number
​ returns
0
, which is a
falsy
value, therefore the
else​
block is executed.

虽然

number
属性存在,
obj.number
返回
0
,这是一个
falsy
值,因此,
else​
块被执行。

So unless you're sure of the range of values that would be used, boolean values and properties in objects should be tested like this:

因此,除非您确定要使用的值的范围,否则应该像这样测试对象中的布尔值和属性:

if(a === false)...
if(object.hasOwnProperty(property))...

令人困惑的加法和串联 (Confusing Addition and Concatenation)

The plus sign

(+)
has two functions in JavaScript: addition and concatenation. Addition is for numbers and Concatenation is for strings. Some developers often misuse this operator.

加号

(+)
在JavaScript中具有两个功能:加法和串联。 加号用于数字,串联用于字符串。 一些开发人员经常滥用此运算符。

For example:

例如:

const num1 = 30;
​​const num2 = "20";
​​const num3 = 30;
​​const word1 = "Java"
​​const word2 = "Script"
​​console.log(num1 + num2);
​​// 3020
​​console.log(num1 + num3);
​​// 60
​​console.log(word1 + word2);
​​// JavaScript
​​

​​When adding strings and numbers, JavaScript converts the numbers to strings, and concatenates all values. For addition of numbers, a mathematical operation is performed.​​

在添加字符串和数字时,JavaScript将数字转换为字符串,并连接所有值。 对于数字加法,将执行数学运算。

结论 (Conclusion)

There are, of course, more mistakes (some trivial, some serious) than the ones listed above. So just make sure you stay up to date with developments in the language.

当然,比上面列出的错误更多(一些琐碎的错误,一些严重的错误)。 因此,只要确保您了解最新的语言发展情况即可。

Studying and avoiding these mistakes will help you build better and more reliable web applications and tools.

研究并避免这些错误将帮助您构建更好,更可靠的Web应用程序和工具。

翻译自: https://www.freecodecamp.org/news/nine-most-common-mistakes-developers-make-in-javascript/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: