10个最常见的JavaScript错误

更新日期: 2019-07-19阅读: 2.3k标签: 错误

这里是10大JavaScript错误:


为了可读性,上面错误的描述都是缩写后的。接下来会深入探讨一下,这些错误发生的原理,并且如何避免触发他们。


1. Uncaught TypeError: Cannot read property

如果你是一个JavaScript开发人员,可能你看到这个错误的次数,比你希望承认的次数还要多。当你在一个未定义undefined的对象上读取一个属性或调用一个方法时,这个错误就会在chrome里触发(当然在其他浏览器中也会报错,但是错误信息不是这样描述的)。在chrome开发者控制台console里,可以测试这个错误:

这个错误出现的原因有很多,最常见的一种场景是:当使用UI组件进行渲染时,声明state不正确。让我们来看下下面这段在真实app中的示例代码片段。我们选取的react的代码,但是同理这种不恰当的声明在vueangular或其他框架中也会出现。

    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>
        );
      }
    }

这里有两点需要注意的:

    一个组件的state(比如上面的this.state)在组件生命周期开始时是未声明的,为undefined。
    当你异步获取数据时,组件在获取到数据之前,无论你获取数据的代码是写在constructor方法,还是componentWillMount或者componentDidMount的生命周期里,至少都会调用一次render方法渲染模板。上面的示例代码运行第一次render的时候,this.state.items为undefined。这意味着本该是ItemList的值,却为undefined,接着你就会在console里看到一个错误”Uncaught TypeError: Cannot read property ‘map’ of undefined“

这个问题修复起来也很简单。最简单的方法:在constructor里初始化时用恰当的默认值赋值给state。

class Quiz extends Component {
  // 在这里添加:
  constructor(props) {
    super(props);

    // 声明state本身,并给他的属性都设置上一个默认值
    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>
    );
  }
}

在你的app中的具体代码可能和上面有区别,但我们还是希望这会给你足够多的线索去修复或避免这个错误。如果没能帮到你,请继续阅读下面的更多例子以及相关的错误。


2.TypeError: ‘undefined’ is not an object

当你在一个未定义undefined的对象上读取一个属性或调用一个方法时,在safari里就会报这个错。你可以再Safari的console控制台里测试这个错误,本质上和上面那个在chrome中出现错误是一样的,只是在Safari用里的错误信息有区别。


3. TypeError: null is not an object

当你去读取一个null对象的属性或调用方法时,会在Safari里出现这个错误。可以在Safari 控制台里测试这个错误。


有趣的是,在JavaScript中的null和undefined是不相等的,所以我们才会得到不同的错误信息。Undefined通常是指一个变量没有被声明,而null表示一个变量的值为空。使用严格相等操作符可以证实他们是不相等的。


在实际项目中有一种出现这种错误的场景:当你在js中想要操作一个dom元素,但这个元素还没加载或者不存在时。这是因为dom的api会在你查找dom元素的结果为空的情况下返回null。
任何处理dom元素的代码必须要放在dom元素被创建完毕之后。JS代码正如html中一样,是从上而下执行的。所以,如果你在html代码里的dom元素之前使用了一个JavaScript标签,并在里面包含了一些内联的js代码,那么这些js代码会在html页面解析之前执行。这时可能就会出现这个错误,因为在加载js代码之前,dom元素还没有被创建好。
在这种情况下,我们可以通过添加一个监听页面是否解析完毕的事件监听来解决问题。一但事件监听器触发,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

当一个未被捕获的错误在跨域时,违背了浏览器的跨域策略,就会出现这个错误。举个例子,你把js代码放在了CDN上面,任何未捕捉的错误发生时(这里指冒泡到window.onerror的监听处理器,而没有try/catch的错误)都只会报一条简单的'Script error'信息,而没有更加详细有帮助的错误信息。这是浏览器的一种安全手段,为了防止跨域传输数据,不允许进行通信。
想要获取到真实详细的错误信息,你可以像这样做:

在header里添加 Access-Control-Allow-Origin 字段

在header(这应该是服务器返回的response header)字段里,把Access-Control-Allow-Origin设为,这样就表示来自任意的域名请求都可以正确地访问到服务器的资源。必要的话也可以指定具体的域名来代替星号,比如:Access-Control-Allow-Origin: www.example.com。但是配置的域名太多的话,处理起来会有点棘手,而且如果你在使用CDN的话还会出现缓存的问题,这样就有点费力不讨好了。更多参考这里

下面举一些在各种环境下配置这个header的示例:
Apache:
在JavaScript代码所在的文件夹目录下,新建一个.htaccess文件,内容如下:

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

Nginx:

在JavaScript代码所在文件夹目录下面,添加add_header命令:

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

HAProxy:

在后端的JavaScript所在文件加入以下内容:

rspadd Access-Control-Allow-Origin:\ *
在JavaScript标签上设置crossorigin="anonymous"

在html代码里,每个设置好了Access-Control-Allow-Origin的js资源,都可以在其JavaScript标签上添加crossorigin="anonymous"。在设置crossorigin="anonymous"之前,确定好header字段都是正确发送了的。在Firefox里,如果js标签上出现了crossorigin属性,但是header里没有Access-Control-Allow-Origin,那么该js将不会被执行。(crossorigin是html5新增的功能,不只是JavaScript标签独有的,比如video、image也可以设置)


5. TypeError: Object doesn’t support property

这个错误发生在IE浏览器中,当你调用一个未定义的方法时,可以在IE的console里测试这个:

这个错误和发生在chrome里的"TypeError: ‘undefined’ is not a function"是相同的,不同的浏览器对于相同的逻辑错误会给出不同的错误信息。
这是一个常见的错误,当你在IE里操作JavaScript的命名空间时。这种情况百分之九十九是因为IE无法将当前作用域的方法绑定给this关键字。举个例子,假设你有一个名叫Rollbar的作用域,里面包含了一个isAwesome函数。正常情况下,你可以用下面这样的语法在Rollbar作用域里引用isAwesome函数:

this.isAwesome();

Chrome,Firefox 和 Opera 会能接受这个语法,但是IE不行。 因此,使用 JS 命名空间时最安全的选择是始终以实际名称空间作为前缀:

Rollbar.isAwesome();


6. TypeError: ‘undefined’ is not a function

调用一个未定义的函数时会出现这个错误,可以在Chrome或Mozilla Firefox的console里测试这个:

随着js代码的编码技巧和设计模式越来越复杂,在回调函数、闭包等各种作用域中this的指向的层级也随之增加,这就是js代码中this/that指向容易混淆的原因。
先来看下这段代码:

function testFunction() {
  this.clearLocalStorage();
  this.timer = setTimeout(function() {
    this.clearBoard();    // 这个this指向谁?
  }, 0);
};

执行上述代码时,会出现错误: "Uncaught TypeError: undefined is not a function."。这是因为你执行setTimeout方法时,其实是执行的window.setTimeout。所以作为参数传递过去的匿名函数,其实是在window作用域下执行的,而window对象并没有clearBoard方法。
一个最简单的、能兼容旧版本浏览器的方法,就是先把this指向赋值给一个变量self,然后在闭包里直接引用这个self变量。像这样:

function testFunction () {
  this.clearLocalStorage();
  var self = this;   // 把this赋值给self,这个作用域就会被保存下来
  this.timer = setTimeout(function(){
    self.clearBoard();  
  }, 0);
};

另外也可以使用bind方法来传递恰当的this指向:

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’

当在chorme中读取一个未定义变量的length属性时,就会出现这个错误。

正常情况下你可以在数组对象上读取这个length属性,但是如果你要使用的数组对象没有被初始化,或者因为作用域的问题而没有正确地获取到,可能就会出现这个错误。来看下面这段代码理解下:

var testArray= ["Test"];

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

testFunction();

当你声明函数的参数时,这些参数就是在函数内部的本地参数。这意味着,你在外部声明的全局变量和本地变量同名了话(都是叫testArray),那在函数内部读取的一定是本地的变量,即传入的参数。
有两种方法解决这样的问题

在函数声明时,去掉这些参数。

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();

把外部的变量作为参数正确地传给函数内部。

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,不能再读取/设置它的属性。否则,就会抛出这个错误。


10. ReferenceError: event is not defined

当您尝试访问未定义的变量或当前作用域无法访问到的变量时,就会出现这个错误。

来自:https://rollbar.com/blog/top-10-javascript-errors/

链接: https://fly63.com/article/detial/4815

解决Cannot read property range of null 错误

vue工程npm run serve/start/dev启动时,node_modules文件报:Cannot read property range of null 错误,该问题是babel-eslint版本更新问题导致的;

HTTP 400 错误 - 请求无效 (Bad request)

在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里;原因:前端提交数据的字段名称或者是字段类型和后台的实体类不一致

js异步错误捕获

我们都知道 try catch 无法捕获 setTimeout 异步任务中的错误,那其中的原因是什么。以及异步代码在 js 中是特别常见的,我们该怎么做才比较?

不能执行已释放Script的代码

父页面初始化声明变量a为数组(数组对象是引用类型,赋值传递的是地址),创建iframe子页面后给父页面变量a赋值,赋值后销毁iframe子页面,再次调用变量a的时候就会抛出异常‘SCRIPT5011:不能执行已释放Script的代码’。

JS错误处理:前端JS/Vue/React/Iframe/跨域/Node

js错误的实质,也是发出一个事件,处理他,error实例对象message:错误提示信息,name:错误名称(非标准属性)宿主环境赋予

nodejs提示 cross-device link not permitted, rename 错误解决方法

文件上传的功能时候,调用fs.renameSync方法错误,这个提示是跨区重命名文件出现的权限问题。先从源文件拷贝到另外分区的目标文件,然后再unlink,就可以了。

Js中使用innerHTML的缺点是什么?

如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断

Web前端开发,必须规避的8个错误点!

现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性。我们收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站。

web前端错误监控

为什么要做前端错误监控?1. 为了保证产品的质量2. 有些问题只存在于线上特定的环境3. 后端错误有监控,前端错误没有监控,前端错误分为两类: 即时运行错误和资源加载错误

自定义错误及扩展错误

当我们在进行开发的时候,通常需要属于我们自己的错误类来反映任务中可能出现的特殊情况。对于网络操作错误,我们需要 HttpError,对于数据库操作错误,我们需要 DbError,对于搜索操作错误,我们需要 NotFoundError,等等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!