Original address:
Rollbar.com/blog/top-10…



For more articles see:
Github.com/elevenbeans…

To give back to our developer community, we looked through the databases of thousands of projects and found the 10 most frequent errors in JavaScript. We tell you what causes these errors and how to prevent them from happening. If you can avoid falling into these “traps”, you’ll be a better developer.

Data is king, and we collected and analyzed the top 10 most common JavaScript errors. The Rollbar collects all errors for each item and summarizes how many times each error occurred. We did this by using “fingerprints” (an algorithm used by rollbar, see rollbar.com/docs/groupi…). Group errors. Basically, if the second mistake is just a repeat of the first mistake, we put the two mistakes in the same group. This will give the user a good overview, rather than a bunch of oppressive dumps as seen in log files.

We focus on the errors that are most likely to affect you and your users. To do this, we rank the errors by looking at the project sets of various companies. If we only looked at the total number of errors per error, the errors generated by projects with high customer volume might overwhelm other errors, resulting in an error data set that is not relevant to most readers.

Here are the Top 10 JavaScript errors:

Each error description has been shortened for ease of reading. Next, let’s dive into each error to determine what causes it and how to avoid creating it.

1. Uncaught TypeError: Cannot read property

If you’re a JavaScript developer, you’ve probably seen this error more times than you’d dare admit. . This error occurs in Chrome when you read an undefined object’s properties or call its methods. You can easily test it in the Chrome developer console.

There are many reasons for this, but a common one is poor initialization of state when rendering UI components.

Let’s take a look at an example that happens in a real application: we chose React, but the same applies to Angular, Vue, or any other framework.

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

There are two important things to achieve here:

  1. The state of the component (such as this.state) fromundefinedStart.
  2. When data is retrieved asynchronously, whether it is in the constructorcomponentWillMountorcomponentDidMountThe component is presented at least once before the data is loaded, and when the Quiz is first presented,this.state.itemsIs undefined. Which in turn meansItemListitemsIs defined asundefined“Uncaught TypeError: Cannot read property ‘map’ of undefined”, and error occurs in the console – “Uncaught TypeError: Cannot read property ‘map’ of undefined”.

This is easy to fix. The simplest way: initialize state with reasonable defaults in the constructor.

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

The specific code in your application may be different, but we hope we’ve given you enough clues to solve or avoid this problem in your application. If not, read on, because we’ll cover more examples of related errors below.

TypeError: ‘undefined’ is not an object

This is an error that occurs when reading a property or calling a method on an undefined object in Safari. You can easily test it in the Safari Developer Console. This is basically the same error for Chrome as mentioned in 1, but Safari uses a different error message prompt.

3. TypeError: null is not an object

This is an error that occurs when reading a property or calling a method on an empty object in Safari. You can easily test it in the Safari Developer Console.

Interestingly, null and undefined are not the same in JavaScript, which is why we see two different error messages. Undefined is usually an unassigned variable, while null indicates that the value is null. To verify that they are not equal, try using the strict equality operator === :

In a real-world example, one scenario where this error can occur is if you try to use elements in JavaScript before they are loaded. The DOM API returns null for a blank object reference.

Any JS code that executes and processes A DOM element should be executed after the DOM element is created. JS code is interpreted from top to bottom as specified in HTML. So, if a DOM element is preceded by a tag, the JS code inside the script tag will be executed when the browser parses the HTML page. This error occurs if the DOM element has not been created before the script is loaded.

In this case, we can solve this problem by adding an event listener that will notify us when the page is ready. Once the addEventListener is triggered, the init() method can use DOM elements.

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

This type of scripting error occurs when uncaught JavaScript errors (errors raised through the window.onerror handler, rather than caught in a try-catch) are restricted by the browser’s cross-domain policy. For example, if you host your JavaScript code on a CDN, any uncaught errors will be reported as “script errors” rather than containing useful stack information. This is a browser security measure designed to prevent the transfer of data across domains that would otherwise not allow communication.

To get a real error message, do the following:

1. Send the ‘access-Control-allow-Origin’ header

Setting the access-Control-allow-Origin header to * indicates proper Access to resources from any domain. If necessary, you can replace the domain with your domain: for example, access-Control-allow-Origin: www.example.com. However, dealing with multiple domains can get tricky, and if you use A CDN, the potential for more caching issues will make you feel like the effort isn’t worth it. See more here.

Here are some examples of how to set this header in various environments:

Apache

In the folder where the JavaScript files are located, create a.htaccess file with the following:

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

Nginx

Add the add_header directive to the location block that provides the JavaScript file:

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

HAProxy

Add the following to the back end where you serve resources for JavaScript files:

1
rspadd Access-Control-Allow-Origin:\ *

In 2.<script>Set in thecrossorigin="anonymous"

In your HTML code, for each script for which you set the Access-Control-Allow-Origin header, set Crossorigin = “anonymous” on the script tag. Before adding the Crossorigin attribute to the script tag, be sure to verify that the above headers are sent correctly. In Firefox, if the Crossorigin attribute exists, but the Access-Control-Allow-Origin header does not, the script will not execute.

TypeError: Object doesn’t support property

This is an error that occurs in IE when you call an undefined method. You can test it in the IE developer console.

This is equivalent to “TypeError:” undefined “is not a function” error in Chrome. Yes, different browsers may have different error messages for the same logical error.

This is a common problem with Internet Explorer L for Web applications that use JavaScript namespaces. In this case, 99.9% of the reason is that IE cannot bind methods in the current namespace to the this keyword. For example, if you have a namespace Rollbar in JS and the method isAwesome. In general, if you are inside the Rollbar namespace, the isAwesome method can be called using the following syntax:

1
this.isAwesome();

Chrome, Firefox, and Opera will embrace this syntax. IE, on the other hand, doesn’t. Therefore, the safest choice when using A JS namespace is to always prefix it with the actual namespace.

1
Rollbar.isAwesome();

TypeError: ‘undefined’ is not a function

This is a Chrome error when you call an undefined function. You can test it in the Chrome developer console and Mozilla Firefox Developer console.

As JavaScript coding techniques and design patterns have become more complex over the past few years, the scope of self-reference in callbacks and closures has increased correspondingly, which is a fairly common source of this/that confusion.

Consider this code snippet:

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

Executing the above code results in the following error: “Uncaught TypeError: undefined is not a function”. The reason you get the above error is that when you call setTimeout(), you are actually calling window.settimeout (). Therefore, an anonymous function passed to setTimeout() is defined in the context of the window object, which has no clearBoard() method.

A traditional, old browser-compatible solution is to simply save your this in a variable that can then be inherited by closures. Such as:

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

Or, in newer browsers, you can pass the appropriate reference using the bind() method:

12345678
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

This is a Chrome error that can occur in some cases. One is when you call a recursive function that doesn’t terminate. You can test it in the Chrome developer console.

In addition, this can happen if you pass values to functions that are out of scope. Many functions only accept a specific range of numbers from their input values. For example: number.toexponential (digits) and number.tofixed (digits) accept numbers from 0 to 20, and number.toprecision (digits) accept numbers from 1 to 21.

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

TypeError: Cannot read property ‘length’ 8. TypeError: Cannot read property ‘length’

This is an error that occurred in Chrome because the length attribute of an undefined variable was read. You can test it in the Chrome developer console.

You will usually find the defined length in the array, but you may encounter this error if the array is not initialized or if the variable name is hidden in another context. Let’s use the following example to understand this mistake.

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

When you declare a function with arguments, those arguments become local arguments in the function’s scope. This means that even if you have variables outside the function named testArray, arguments with the same name in a function are treated as local arguments.

You have two ways to solve your problem:

Delete arguments from function declarations (in fact, you want to access variables declared outside the function, so you don’t need function arguments) :

12345678910
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. Call this function with the declared array:

123456789
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

When we try to access an undefined variable, it always returns undefined, and we cannot get or set any undefined properties. In this case, the application will throw “Uncaught TypeError: Cannot set Property”.

For example, in Chrome:

If the test object does not exist, “Uncaught TypeErrorUncaught TypeError: Cannot set Property” will be thrown.

10. ReferenceError: event is not defined

This error is raised when you try to access an undefined variable or a variable that is outside the current scope. You can easily test it in Chrome.

If you encounter this error when using the event handling system, be sure to use the event object passed in as a parameter. Older browsers like Internet Explorer provide a global variable event, but not all browsers support it. Libraries like jQuery attempt to standardize this behavior. However, it is best to use the function passed in to the event handler.

123456
function myFunction(event) {    event = event.which || event.keyCode;    if(event.keyCode===13){       alert(event.keyCode);    }}

conclusion

We hope you’ve learned something new, that you can avoid future mistakes, or that this guide has helped you solve a headache.

Still, even with best practices, unexpected errors can occur in production. It’s important to be able to see errors that affect users and have good tools to resolve them quickly. Recommend the Rollbar.

Bootleg time

This should be the last one of the year. By the way, a preview of the next wave of “big news” :

CtripFE, a Web mobile React component library: github.com/CtripFE/ird…

Name to be determined, continuous integration ing, welcome issue/PR.