1000多个项目中的十大JavaScript错误以及如何避免

通过统计数据库中的1000多个项目,我们发现在 JavaScript 中最常出现的错误有10个。下面会向大家介绍这些错误发生的原因以及如何防止。

对于这些错误发生的次数,我们是通过收集的数据统计得出的。Rollbar 会收集每个项目中的所有错误,并总结每个错误发生的次数,然后通过各个错误的特征进行分组。

下图是发生次数最多的10大 JavaScript 错误:

下面开始深入探讨每个错误发生的情况,以便确定导致错误发生的原因以及如何避免。

1.   Uncaught TypeError: Cannot Read Property

这是 JavaScript 开发人员最常遇到的错误。当你读取一个属性或调用一个未定义对象的方法时,Chrome 中就会报出这样的错误。

导致这个错误发生的原因有很多,常见的一种情况是在渲染 UI 组件时,不正确地初始化状态。我们来看一个真实的应用程序中发生这种情况的例子。

class Quiz extends Component {
  componentWillMount() {
    axios.get(‘/thedata‘).then(res => {
      this.setState({items: res.data});
    });
  }
  render() {
    return (
      <ul>
        {this.state.items.map(item =>
          <li key={item.id}>{item.name}</li>
        )}
      </ul>
    );
  }
}

以上代码有两个重要方面:

  1. 一是组件的状态(例如 this.state),在开始生命周期之前是 undefined 状态。
  2. 二是当通过异步的方式获取数据时,无论是在构造函数中 componentWillMount 中,还是在构造函数中提取 componentDidMount,组件在数据加载之前至少会渲染一次。当检测首次渲染时,会发现 this.state.items 是未定义的。此时就会出现一个错误 -“Uncaught TypeError: Cannot read property ‘map’ of undefined" in the consol”。

解决的方法很简单:在构造函数中使用合理的默认值进行状态初始化。

class Quiz extends Component {
  // Added this:
  constructor(props) {
    super(props);
    // Assign state itself, and a default value for items
    this.state = {
      items: []
    };
  }
  componentWillMount() {
    axios.get(‘/thedata‘).then(res => {
      this.setState({items: res.data});
    });
  }
  render() {
    return (
      <ul>
        {this.state.items.map(item =>
          <li key={item.id}>{item.name}</li>
        )}
      </ul>
    );
  }
}

2. TypeError: ‘undefined’ Is Not an Object (evaluating...)

这是在 Safari 中读取属性或调用未定义对象上的方法时发生的错误,这与 Chrome 的上述错误基本相同,只是 Safari 使用不同的错误消息。

3. TypeError: Null Is Not an Object (evaluating...)

这是在 Safari 中读取属性或调用空对象上的方法时发生的错误。

有趣的是,在 JavaScript 中,null 和 undefined 是两种不同的类型,这就是为什么会出现两个不同的错误消息。未定义通常是一个尚未分配的变量,而 null 则表示该值为空。要验证它们不相等,请使用严格的相等运算符:

在实际情况中,导致这种错误的原因之一是:在元素加载之前,就尝试在 JavaScript 中使用 DOM 元素。这是因为 DOM API 对于空白的对象引用返回 null。

任何执行和处理 DOM 元素的 JS 代码,都应该在创建 DOM 元素之后执行。JS 代码按照 HTML 中的规定自上而下进行解释。因此,如果在 DOM 元素之前存在标签,则脚本标签内的 JS 代码就会在浏览器分析 HTML 页面时执行。如果在加载脚本之前尚未创建 DOM 元素,就会出现这样的错误。

在这个例子中,我们可以通过添加一个事件侦听器来解决这个问题,事件侦听器会在页面准备就绪时通知我们。一旦 addEventListener 被触发,该 init(  ) 方法就可以使用 DOM 元素。

<script>
  function init() {
    var myButton = document.getElementById("myButton");
    var myTextfield = document.getElementById("myTextfield");
    myButton.onclick = function() {
      var userName = myTextfield.value;
    }
  }
  document.addEventListener(‘readystatechange‘, function() {
    if (document.readyState === "complete") {
      init();
    }
  });
</script>
<form>
  <input type="text" id="myTextfield" placeholder="Type your name" />
  <input type="button" id="myButton" value="Go" />
</form>

4. (unknown): Script Error

当未捕获的 JavaScript 错误违背跨边界原则时,就会发生脚本错误。例如,如果将 JavaScript 代码托管在 CDN 上,则任何未被捕获的错误(通过 window.onerror 处理程序发出的错误,而不是 try-catch 中捕获到的错误)将仅报告为“脚本错误”。这是浏览器的一种安全措施,主要用于防止跨域传递数据的情况出现。

要获取真实的错误消息,需要执行以下操作:

1.    Access-Control-Allow-Origin

将 Access-Control-Allow-Origin 设置为 *, 表示可以从任何域正确访问资源。* 如有必要,也可以用自己的域名进行替换,例如:

Access-Control-Allow-Origin: www.example.com。

以下是在各种环境中设置的一些示例:

Apache

在 JavaScript 文件夹中,创建一个 .htaccess 文件,并包含以下内容:

Header add Access-Control-Allow-Origin "*"

Nginx

将 add_header 指令添加到提供 JavaScript 文件的 location block 中:

location ~ ^/assets/ {
    add_header Access-Control-Allow-Origin *;
}

HAProxy

将以下内容添加到提供 JavaScript 文件的静态资源配置后端:

rspadd Access-Control-Allow-Origin:\ *

2.    在脚本标签上设置crossorigin =“anonymous”

在你的 HTML 源代码中,为每一个脚本设置 Access-Control-Allow-Origin,在设置 SCRIPT 标签中,设置 crossorigin="anonymous"。在将 crossorigin 属性添加到脚本标签之前,请确保正在向脚本文件发送 header。在 Firefox 中,如果 crossorigin 属性存在但 Access-Control-Allow-Origin 标题不存在,则脚本不会执行。

5. TypeError: Object Doesn’t Support Property

当调用未定义的方法时,IE 中会发生这样的错误。

这相当于 Chrome 中的 “undefined’ is not a function” 错误。对于相同的逻辑错误,不同的浏览器可能会有不同的错误消息。

这是在 IE 的 Web 应用程序中使用 JavaScript 命名空间出现的一个常见问题。出现这种情况的绝大部分原因是IE无法将当前名称空间内的方法绑定到this关键字。例如,如果你有 JS Rollbar 方法的命名空间 isAwesome。通常,如果位于 Rollbar 命名空间内,则可以使用以下语法调用该 isAwesome 方法:

this.isAwesome();

Chrome、Firefox 和 Opera 接受这种语法,IE则不接受。因此,使用 JS 命名空间时最安全的做法是:始终以实际名称空间作为前缀。

Rollbar.isAwesome();

6. TypeError: ‘undefined’ Is Not a Function

当调用未定义的函数时,Chrome 中就会发生这样的错误。

随着 JavaScript 编码技术和设计模式在过去几年中变得越来越复杂,回调和闭包中的自引用范围也相应增加,这是造成这种混乱现象的主要来源。

正如下面的示例代码片段:

function testFunction() {
  this.clearLocalStorage();
  this.timer = setTimeout(function() {
    this.clearBoard();    // what is "this"?
  }, 0);
};

执行上面的代码会导致以下错误:“Uncaught TypeError: undefined is not a function。” 发生以上错误的原因是,当你调用 setTimeout(  )  时,实际上是在调用 window.setTimeout(  ),传递给 setTimeout(  ) 的匿名函数是在窗口对象的上下文中定义的,而该窗口对象没有 clearBoard(  ) 方法。

符合旧版浏览器的解决方案是以变量的方式简单地将引用保存在 this 中,然后通过闭包继承。例如:

function testFunction () {
  this.clearLocalStorage();
  var self = this;   // save reference to ‘this‘, while it‘s still this!
  this.timer = setTimeout(function(){
    self.clearBoard();
  }, 0);
};

或者,在较新的浏览器中,使用 bind(  ) 方法传递引用:

function testFunction () {
  this.clearLocalStorage();
  this.timer = setTimeout(this.reset.bind(this), 0);  // bind to ‘this‘
};
function testFunction(){
    this.clearBoard();    //back in the context of the right ‘this‘!
};

7. Uncaught RangeError: Maximum Call Stack

这是在很多种情况,Chrome 中发生的错误,一种情况是当你调用一个不会终止的递归函数时。

如果将值传递给超出范围的函数,也可能会发生这种情况。许多函数只接受特定范围内的数字输入值。例如,Number.toExponential( digits ) 与 Number.toFixed( digits) 接受的参数范围为从0到20,而 Number.toPrecision( digits ) 接受的数字范围为从1至21。

var a = new Array(4294967295);  //OK
var b = new Array(-1); //range error
var num = 2.555555;
document.writeln(num.toExponential(4));  //OK
document.writeln(num.toExponential(-2)); //range error!
num = 2.9999;
document.writeln(num.toFixed(2));   //OK
document.writeln(num.toFixed(25));  //range error!
num = 2.3456;
document.writeln(num.toPrecision(1));   //OK
document.writeln(num.toPrecision(22));  //range error!

8. TypeError: Cannot Read Property ‘length’

这是 Chrome 中发生的错误,因为读取了未定义长度属性的变量。

通常在数组中能够找到定义的长度,但是如果数组未初始化或变量名在另一个上下文中隐藏,则可能会出现这种错误。让我们用下面的例子来解释这种错误。

var testArray= ["Test"];
function testFunction(testArray) {
    for (var i = 0; i < testArray.length; i++) {
      console.log(testArray[i]);
    }
}
testFunction();

当用参数声明一个函数时,这些参数会成为本地参数。这意味着即使你有名称变量 testArray,函数中具有相同名称的参数仍会被视为本地参数

有两种方法可以解决这个问题:

1. 删除函数声明语句中的参数:

var testArray = ["Test"];
/* Precondition: defined testArray outside of a function */
function testFunction(/* No params */) {
        for (var i = 0; i < testArray.length; i++) {
              console.log(testArray[i]);
        }
}
testFunction();

2. 调用传递给我们声明的数组函数:

var testArray = ["Test"];
function testFunction(testArray) {
for (var i = 0; i < testArray.length; i++) {
        console.log(testArray[i]);
        }
}
testFunction(testArray);

9. Uncaught TypeError: Cannot Set Property

当尝试访问未定义的变量时,总会返回 undefined。我们也无法获取或设置 undefined 的任何属性。在这种情况下,应用程序将抛出“Uncaught TypeError cannot set property of undefined”。

例如,在 Chrome 浏览器中,如果 test 对象不存在,就会出现这种错误:

所以就需要在访问变量之前,对变量进行定义。

10. ReferenceError: Event Is Not Defined

尝试访问未定义的变量或当前范围之外的变量时会引发此错误。

如果在使用事件处理系统时遇到此错误,请确保使用传入的事件对象作为参数。IE 这样的浏览器提供了全局变量事件,Chrome 会自动将事件变量附加到处理程序中,Firefox 则不会自动添加事件变量。

document.addEventListener("mousemove", function (event) {
  console.log(event);
})

结论

事实证明很多这些 null 或 undefined 的错误是普遍存在的。 一个类似于 Typescript 这样的好的静态类型检查系统,当设置为严格的编译选项时,能够帮助开发者避免这些错误。

最后也希望通过本文,可以帮助开发者更好避免或是应对以上的10种错误。

原文链接:https://dzone.com/articles/top-10-javascript-errors-from-1000-projects-and-ho-1

原文地址:https://www.cnblogs.com/mumusen/p/8508926.html

时间: 2024-10-06 11:00:35

1000多个项目中的十大JavaScript错误以及如何避免的相关文章

职场中的十大低级错误

一.诚实 无论任何人和你交流,或者,为了某一目的,你和别人交流,记得说实话,你可以保持不说的权利,一旦开口,一定是以诚待人,实话实说. 尤其是上司向你询问一些事情,知道就是知道,不知道,别信口开河.另外,没有不透风的墙,你说的每一句话,都会被传出去,所以,千万别撒谎. 二.有始有终 职场新人,经常会接受一些任务,有的人不知道如何做,就拖延了,上级有时候会忘记,于是,新人庆幸老板没有继续找他.熟不知,有任务,必然有原因,即便是老板忘记,自己也该及时汇报进展,做得好与不好,姑且不论,但一定要给个交代

机器学习与数据挖掘中的十大经典算法

背景: top10算法的前期背景是吴教授在香港做了一个关于数据挖掘top10挑战的一个报告,会后有一名内地的教授提出了一个类似的想法.吴教授觉得非常好,开始着手解决这个事情.找了一系列的大牛(都是数据挖掘的大牛),都觉得想法很好,但是都不愿自己干.原因估计有一下几种:1.确实很忙2.得罪人3.一系列工作很繁琐等等.最后和明尼苏达大学的Vipin Kumar教授一起把这件事情承担下来.先是请数据挖掘领域获过kdd和icdm大奖的十四个牛人提名候选,其中一人因为确实很忙,正从ibm转行到微软,吴教授

数学建模学习笔记(建模中的十大常用算法总结)

数学建模中的十大常用算法 1.    蒙特卡洛方法: 又称计算机随机性模拟方法,也称统计实验方法.可以通过模拟来检验自己模型的正确性. 2.    数据拟合.参数估计.插值等数据处理 比赛中常遇到大量的数据需要处理,而处理的数据的关键就在于这些方法,通常使用matlab辅助,与图形结合时还可处理很多有关拟合的问题. 3.    规划类问题算法: 包括线性规划.整数规划.多元规划.二次规划等:竞赛中又很多问题都和规划有关,可以说不少的模型都可以归结为一组不等式作为约束条件,几个函数表达式作为目标函

Go开发中的十大常见陷阱[译]

原文: The Top 10 Most Common Mistakes I've Seen in Go Projects 作者: Teiva Harsanyi 译者: Simon Ma 我在Go开发中遇到的十大常见错误.顺序无关紧要. 未知的枚举值 让我们看一个简单的例子: type Status uint32 const ( StatusOpen Status = iota StatusClosed StatusUnknown ) 在这里,我们使用iota创建了一个枚举,其结果如下: Stat

Java十大低级错误

前言 本文档根据java开发人员在编码过程中容易忽视或经常出错的地方进行了整理,总结了十个比较常见的低级错误点,方便大家学习. Java十大低级错误 不能用"=="比较两个字符串内容相等. 对list做foreach循环时,循环代码中不能修改list的结构. 日志和实际情况不一致:捕获异常后没有在日志中记录异常栈. 魔鬼数字. 空指针异常. 数组下标越界. 将字符串转换为数字时没有捕获NumberFormatException异常. 对文件.IO.数据库等资源进行操作后没有及时.正确进

如何在程序开发项目中选择合适的 JavaScript 框架,节省时间和成本的9款极佳的JavaScript框架介绍

从技术上来看,iOS,Android 和 Windows Phone 上的移动应用是使用不同的程序语言开发的,iOS 应用使用 Objective-C,Android 应用使用 Java,而 Windows Phone 应用使用 .NET. .随着 JavaScript,CSS 和 HTML 知识技能的提升,相信你也可以构建一个超赞的移动应用.在这篇博客里,我们将会介绍一些极好的 JavaScript 移动应用程序开发框架. 说到网络开发,就不得不说 JavaScript,这是一款很有前途的程序

json在项目中的应用大总结

一.摘要 刚开始接触json的时候,那时候还不太清楚json到底是个什么东西,然后就在项目中使用了它.因为没有搞明白json的本质,所以刚开始使用json的时候走了不少弯路.这次总结一些json的知识,总结主要是想梳理一下自己使用json的一些应用场景,让自己对json有一个更深刻的认识,以后在项目中可以更加熟练的应用它. 二.总结: 1.json在前端中的应用: a)ajax+json使用场景: ajax处理登录验证信息  解析json格式的String类型对象和ajax获得服务端的响应数据的

Database项目中关于Procedure sp_refreshsqlmodule_internal的错误

最近项目中发现一怪问题,使用DB项目发布数据库时,总提示 “(110,1): SQL72014: .Net SqlClient Data Provider: Msg 1222, Level 16, State 56, Procedure sp_refreshsqlmodule_internal, Line 67 Lock request time out period exceeded. An error occurred while the batch was being executed.”

T-SQL中的十大注意事项

转载自:http://www.cnblogs.com/CareySon/archive/2012/10/11/2719598.html 1.在生产环境中不要出现Select * 这一点我想大家已经是比较熟知了,这样的错误相信会犯的人不会太多.但我这里还是要说一下. 不使用Select *的原因主要不是坊间所流传的将*解析成具体的列需要产生消耗,这点消耗在我看来完全可以忽略不计.更主要的原因来自以下两点: 扩展方面的问题 造成额外的书签查找或是由查找变为扫描 扩展方面的问题是当表中添加一个列时,S