开发人员在JavaScript中犯的9个最常见错误(以及如何解决)
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
setTimeoutfunction 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
secondNumberis undefined. At the time of running
firstNumber + secondNumber,
secondNumberis still undefined because the
setTimeoutfunction 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
)
thisis 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
undefinedbecause
thishas lost reference to the object's properties (including name).
第一个结果是JavaScript
因为
this.name正确指向对象的name属性。 第二个结果是
undefined,因为
this已经失去参考对象的属性(包括名称)。
This is because
thisdepends 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
thisin
obj.printName() points directly to
obj. The
this in
obj.printNameIn2Secspoints directly to
obj. But the
thisin the callback function of
setTimeoutdoes 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
setTimeoutis 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
obj1and
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
localStoragefor saving values. But a common mistake is trying to save arrays and objects as-is in the
localStorage.
localStorageonly 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
.namewould result in an error. This is because
[Object Object]is a string now, without a
nameproperty.
这样保存对象时,将很难访问它们。 对于对象例如,访问对象等
.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
NaNbecause
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
trueand
1 and
truereturns
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
falsyvalue, therefore the
elseblock 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/
- Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决的方法
- 开发常见错误解决(6)WSE3.0未处理的WebException,未处理的Web异常,基础连接以及关闭
- Android开发中的9个常见错误和解决方法
- Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法
- 开发常见错误解决(6)WSE3.0未处理的WebException,未处理的Web异常,基础连接以及关闭
- 开发人员经常犯一些低级错误如何解决
- 如何用 Android Studio 导入开源项目以及常见错误的解决办法
- 9个常见的Android开发错误及解决办法
- 9个常见的Android开发错误及解决办法
- 如何用 Android Studio 导入开源项目以及常见错误的解决办法
- 9个常见的Android开发错误及解决办法
- 开发中常见git操作以及错误解决办法
- 9个常见的Android开发错误及解决办法
- Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法
- 开发常见错误解决(3)VS2005调试程序出错,绑定句柄无效 Terminal Services
- 错误文件ORACLE 常见错误以及解决办法
- WCF分布式开发常见错误解决(1):添加服务引用出错
- 挑灯夜战 css hack 再次学习 IE浏览器常见的9个css Bug以及解决办法
- mysql ab复制过程中的常见错误,以及解决方法
- MFC编程中常见错误及如何解决