• 赚钱入口【需求资源】限时招募流量主、渠道主,站长合作;【合作模式】CPS长期分成,一次推广永久有收益。主动打款,不扣量;

JavaScript中常犯的9个错误及解决方式

JavaScript rin, seun 1年前 (2020-07-01) 296次浏览 0个评论

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

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

混淆赋值(=)和相等(==,===)运算符

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

这是一个例子:

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

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

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

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

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

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

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

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

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

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

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

误认为回调是同步的

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

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

一个示例是全局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

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

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

这是一个错误:

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

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

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

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

错误引用 this​

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

这是使用时常见错误的示例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

第一个结果是JavaScript因为this.name正确指向了对象的name属性。第二个结果是undefined因为this​丢失了对对象属性(包括名称)的引用。

这是因为this​取决于调用该函数所驻留的函数的对象。this每个函数中都有一个变量,但它指向的对象由调用它的对象确定。

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

对于要调用的对象setTimeout​obj.setTimeout...​将执行类似的操作。由于没有对象调用该函数,因此使用默认对象(window)。

name在窗口不存在,从而导致undefined

最好的方式去保留提及thissetTimeout是使用bind​call​apply或箭头功能(在ES6介绍)。与普通功能不同,箭头功能不会创建自己的功能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

忽略对象可变性

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

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

obj1​并且obj2与在对象中存储对象的位置具有相同的引用。

在数组中:

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

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

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

最佳做法是在要复制对象时始终为新对象创建新引用。为此,rest运算符(...​  ES6中引入)是一个完美的解决方案。

例如,在键值对象中:

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

数组中

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

将数组和对象保存到localStorage

有时,在使用JavaScript时,开发人员可能想利用localStorage保存值。但是一个常见的错误是试图将数组和对象原样保存在中localStoragelocalStorage只接受字符串。

为了保存对象,JavaScript将对象转换为字符串。结果是[Object Object]对象的结果,数组元素的结果是逗号分隔的字符串。

例如:

​​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

这样保存对象时,将很难访问它们。对于对象示例,像.name​这样访问对象将导致错误。这是因为[Object Object]现在是一个字符串,没有​name属性。

将对象和数组保存在本地存储中的更好方法是使用JSON.stringify​(用于将对象转换为字符串)和JSON.parse​(用于将字符串转换为对象)。这样,访问对象变得容易。

上面代码的正确版本是:

​​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

不使用默认值

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

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

结果是NaN​因为aundefinedbundefined​。通过使用默认值,可以防止类似的错误。例如:

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

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

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

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

变量命名不正确

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

例如:

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

该变量discount可以,但是ptotal​呢?总共是什么?更好的做法是:

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

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

正确命名变量将使贡献者容易理解项目的工作方式。

检查布尔值

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

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

在JavaScript中,一个松散的比较0false回报true以及1true​返回true。这意味着如果isRaining1isRaining将会是true

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

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

尽管number属性存在,但obj.number返回值0是一个falsy值,因此将else​执行该块。

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

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

令人困惑的加法和串联

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

例如:

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
​​

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

喜欢 (0)

您必须 登录 才能发表评论!