11 种糟糕的 JavaScript 编写方式

开发 前端
JavaScript 是现代 Web 开发不可或缺的一部分,但它有一些需要注意的陷阱。在本文中,我们将介绍10种常见的 JavaScript 编写方式,以帮助您避免一些常见的错误和陷阱。

JavaScript 是现代 Web 开发不可或缺的一部分,但它有一些需要注意的陷阱。在本文中,我们将介绍10种常见的 JavaScript 编写方式,以帮助您避免一些常见的错误和陷阱。

1.隐式类型转换

隐式类型转换是指 JavaScript 在运行时自动将一种数据类型转换为另一种数据类型。 

例如,当您使用加号连接两个字符串时,JavaScript 会自动将它们转换为字符串并连接它们。虽然这看起来很方便,但它经常会导致问题,尤其是对于没有经验的开发人员而言。

let result =  "3"  +  4  +  5 ; // '345' 
let result2 =  3  +  4  +  "5" ; // '75'

上面代码中,第一行的输出结果是字符串‘345’,第二行的输出结果是字符串‘75’。这是因为 JavaScript 在处理加号时会将数字转换为字符串,然后进行拼接操作。因此,当您使用加号连接数字和字符串时,必须小心避免意外行为。

2.使用var声明变量

在 ES6 之前,在 JavaScript 中声明变量的唯一方法是使用 var 关键字。但是var存在一些作用域问题,容易造成变量污染等问题。因此,最好使用 let 或 const 来声明变量,它们是块级作用域。

function  example () { 
  var foo =  "bar" ; 
  if ( true ) { 
    var foo =  "baz" ; 
    console . log (foo); // 'baz'
   } 
  console . log (foo); // 'baz'
 }
function  example2 () { 
  let foo =  "bar" ; 
  if ( true ) { 
    let foo =  "baz" ; 
    console . log (foo);// 'baz'
   } 
  console . log (foo); // 'bar'
 } 
example (); 
example2 ();

在上面的代码中,当第一个示例 var 声明变量时,内部的 foo 覆盖了外部的 foo,导致两者的输出都是字符串 'baz'。 

在第二个例子 let 中,声明变量后,内部的 foo 只存在于内部作用域中,不会影响外部的 foo。

再比如下面这个面试中经常遇到的问题:

for ( var i =  0 ; i <  5 ; i ++ ) { 
  setTimeout ( function () { 
    console . log (i); 
  }, 1000 ); 
} 
// output 5, 5, 5, 5, 5

这是因为setTimeout的回调函数是异步执行的,执行的时候i的值已经变成5了,可以用let或者closure来解决这个问题。

3、DOM操作频繁

直接操作 DOM 是非常低效的,因为这样做会导致页面重复重新渲染,从而降低性能和用户体验。 

相反,应该使用更高效的方式来操作 DOM,比如减少 DOM 查询次数,使用虚拟 DOM 技术等。

// not recommended
document.getElementById('my-button').addEventListener('click', function() {
  document.getElementById('my-text').innerText = 'Hello, world!';
});


// recommended
const myText = document.getElementById('my-text');
document.getElementById('my-button').addEventListener('click', function() {
  myText.innerText = 'Hello, world!';
});

在上面的代码中,第一个示例在每次单击按钮时重新查询 DOM 并更新它,而第二个示例仅查询一次 DOM,然后更新元素的文本内容。

4.修改原型对象

修改原型对象可能会导致一些意想不到的问题。例如:

Array.prototype.sum = function() {
  return this.reduce(function(a, b) {
    return a + b;
  }, 0);
};


var arr = [1, 2, 3];
console.log(arr.sum()); // 6

虽然上面的代码工作正常,但它可能会对其他部分产生意想不到的影响。为了避免这个问题,我们应该尽量避免修改原型对象。

5.使用全局变量

全局变量是 JavaScript 中常见的一种变量类型,但是它们会引起命名冲突等问题。因此,最好避免使用全局变量并以模块化方式组织代码。

// not recommended
function foo() {
  globalVar = "bar";
}


// recommended
const myModule = (function() {
  const localVar = "baz";


  function foo() {
    // do something with localVar
  }


  return {
    foo: foo
  };
})();

在上面的代码中,第一个例子使用了一个全局变量globalVar,它可能会被其他代码覆盖。 

第二个例子使用IIFE(Immediately Invoked Function Expressions)创建一个模块,其中变量只在模块内部可见,不会影响其他代码。

6.忽略分号

JavaScript 允许在语句末尾省略分号,但这往往会导致一些错误,尤其是在代码被缩小或合并时。因此,建议始终以分号结束语句以避免潜在问题。

// not recommended
let x =  1 
let y =  2 
// recommended
let x =  1 ; 
let y =  2 ;

在上面的代码中,第一个示例省略了分号,这可能会导致一些意外行为。第二个例子显式添加了分号,更加规范。

7. 使用 for-in 循环

for-in 循环是一种遍历对象属性的方法,但它有一些缺点。因为它不仅会遍历对象本身的属性,还会遍历从原型链继承的属性,这可能会导致一些意想不到的结果。

const person = { 
  name :  "Alice" , 
  age :  30 , 
  gender :  "female"
 }; 
// not recommended 
for ( const key in person) { 
  console . log (person[key]); 
} 
// recommended 
Object . keys (person). forEach (key =>  console . log (person[key]));

上面代码中,第一个例子使用for-in循环遍历对象属性,而第二个例子使用Object.keys()方法获取对象自身的属性名,并配合forEach()方法来获取 遍历。

8.比较NaN

NaN 是一种特殊类型的数值,表示Not-a-Number(不是数字)。但是,由于 NaN 不等于任何值,所以在比较 isNaN() 时需要用一个函数来判断。

// not recommended
if (x == NaN) {
  // do something
}


// recommended
if (isNaN(x)) {
  // do something
}

上面代码中,第一个例子错误地使用了相等运算符来比较NaN,而第二个例子使用了isNaN()函数来进行判断。

9.使用eval() 

eval() 是一种执行字符串代码的方法,但它容易引起安全问题和性能问题。因此,最好避免在生产环境中使用 eval()。

// not recommended
eval("console.log('Hello, world!')");


// recommended
const code = "console.log('Hello, world!')";
Function(code)();

在上面的代码中,第一个示例使用 eval() 函数来执行字符串代码,而第二个示例使用 Function() 函数来创建一个新函数并执行它。

10.忽略错误处理

忽略错误处理是一个常见的错误,因为它会导致代码崩溃。例如:

try { 
  // some code
 } catch (e) {}

虽然抛出异常的这段代码可能无关紧要,但如果异常处理不当,它可能会在开发或运行时导致问题。

为了避免这个问题,我们应该始终正确处理异常,例如通过记录或显示用户友好的错误消息。

11. 传递函数参数时忘记绑定this

将函数作为参数传递时,需要注意绑定this的值。例如:

const obj = { 
  name :  'Alice' , 
  greet :  function () { 
    console . log ( 'Hello, '  +  this .name); 
  } 
}; 
setTimeout (obj. greet, 1000 ); // Hello, undefined

正确的写法应该是使用bind方法:

const obj = { 
  name :  'Alice' , 
  greet :  function () { 
    console . log ( 'Hello, '  +  this .name); 
  } 
}; 
setTimeout (obj. greet . bind (obj), 1000 ); // Hello , Alice

结语

JavaScript 是现代 Web 开发不可或缺的一部分,它为我们提供了丰富的功能和灵活性,在编写 JavaScript 代码时,我们应该尽量保持代码的可读性、简洁性和可维护性,以便构建出色的 Web 应用程序。

责任编辑:华轩 来源: web前端开发
相关推荐

2012-05-10 15:21:50

JavaScript

2023-05-28 23:23:44

2024-08-20 15:23:27

JavaScript开发

2013-12-10 10:04:15

编程生产方式

2012-09-17 10:35:41

JavaScriptJS代码

2017-06-26 10:35:58

前端JavaScript继承方式

2017-06-14 16:44:15

JavaScript原型模式对象

2020-06-12 08:28:29

JavaScript开发技术

2023-05-22 08:03:28

JavaScrip枚举定义

2022-03-25 14:47:24

Javascript数据类型开发

2021-07-14 10:31:15

JavaScript开发 技巧

2022-05-10 10:28:21

JavaScript代码

2021-11-12 23:41:27

Windows 11Windows微软

2019-09-02 09:30:13

LinuxNASAApple

2018-06-04 12:45:53

苹果iOS 11操作系统

2016-05-25 10:03:51

JavaScript内存泄露

2020-05-06 11:29:29

UX设计钓鱼攻击用户体验

2022-09-14 09:37:17

JavaScript默认导出

2020-09-23 16:31:38

C++C++11启动线程

2023-12-19 16:43:01

点赞
收藏

51CTO技术栈公众号