未加星标

Tips and Tricks for Debugging Client-side JavaScript

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二05 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏

Debugging client-side javascript can be a frustrating experience. The environment in which your code is running means a large number of things could go wrong. Race conditions, browser feature compatibility, dependency issues and resources failing to download can seem outside of your control.

These issues can be handled by reducing the number of points of failure and simplifying how assets are loaded. Another main source of frustration can come from the language of JavaScript itself. Relying on the language to enforce good practices or even consistent syntax (like many other modern languages now do) simply doesn’t work.

In this article, I’ve outlined a few tips on debugging client-side Javascript, and also how to avoid bugs as you develop.

New-lines and Semicolons

In JavaScript new-lines and semicolons have unexpected behavior in some cases. A language feature called ASI (Automatic Semicolon Insertion) causes statements which aren’t terminated by semicolons to be implicitly appended with one in cases such as the code being syntactically invalid.

For example:

while (a < b) { ... a++ }

Would effectively be the same as:

while (a < b) { ... a++; }

This may seem like a nice language feature which enables you to reduce the amount of typing and syntactic clutter. However, it can lead to ambiguous and sometimes incorrect code.

For example:

function calculate(a, b) { var c = a + b return c }

The above function looks like it should calculate a value, place it in a local variable then return that variable. In actuality it calculates the variable and assigns it to variable c, then returns undefined .

While this may not be the most normal way to format your code, in some cases it may be neater, especially if you are working with long expressions. It’s good to keep in mind that in cases like these the newline character after the return statement causes a semicolon to be automatically inserted.

Always explicitly end statements with semicolons and ensure return statements are always followed by the value to be returned on the same line.

Deserialization and ‘eval’

Serializing and deserializing JavaScript objects is a common operation, especially when communicating with various web APIs and storage mechanisms. It’s important to be careful when deserializing as you can easily execute foreign code if you’re not careful.

One way is the evalfunction. This evaluates any string as if it were JavaScript code. As running ‘eval’ on a serialized object would return an object literal, this may seem like a good way to deserialize data like foreign API responses, serialized objects in cookies or local storage. However, if somehow the serialized payload was modified by an attacker he could easily inject statements which steal user credentials or perform harmful actions.

One way is the eval function. This evaluates any string as if it were JavaScript code. As running ‘eval’ on a serialized object would return an object literal, this may seem like a good way to deserialize data like foreign API responses, serialized objects in cookies or local storage. However, if somehow the serialized payload was modified by an attacker he could easily inject statements which steal user credentials or perform harmful actions.

The safe way to deserialize an object is to use parse method on the JSON object.

Don’t do:

var myObject = eval(mySerializedObject);

Do:

var myObject = JSON.parse(mySerializedObject); Dynamic types

JavaScript is a dynamically typed language. This means that variables can store values of any type and this could change at any time. However, it’s a good step to remember when you aredebugging client-side JavaScript.

Eg:

var a = 'apple'; //a is a string a = 5; //a is a number a = ['apple', 'banana', 'carrot']; //a is an array of strings a = function(a, b) { return a * b; }; //a is a function which expects two numbers as arguments

Because of this capability, many issues may arise when a variable is holding a value type you didn’t expect. Therefore, how you name and utilize variables is very important. Generally it’s not a good idea to reuse the same variable for different value types over and over unless under very specific controls. This is especially important in code with lots of branches. If the same value is being modified again and again it may be hard to reason about what the variable contains at any one point in the code, which is likely to lead to bugs.

Some good practices include only assigning a variable once. This is common in functional programming. If you enforce this yourself, you shouldn’t run into issues where you don’t know what something is because it will always be the same as what it was initially assigned (assuming it hasn’t mutated itself).

Another consideration related to dynamic typing is that the type of a variable may automatically be cast to another type in some cases. For instance if we pass the string '5' into a function function(input) { return input * 10; } we may expect an error as a string cannot intuitively be multiplied, however the function will actually return the value 50 . This is because the value '5' has been implicitly converted to a number before being multiplied.

In this example it may be relatively easy to understand why and what happened but in larger applications where objects with many fields may be being operated on an implicit type conversion such as above may result in situations which you wouldn’t expect.

For this reason it’s important to (in cases of ambiguous types) check the type of the variables acted upon and handle accordingly.

For example the ‘example’ function could handle this with an exception this would be helpful mainly for debugging and determining where and why this value is being passed.

function(input) { if (typeof(input) !== 'number') { throw new Error('Invalid argument type'); } return input * 10; }

Another consideration is related to equality checking. Modern JavaScript provides two means for checking the equality of values: loose equality is checked using the == operator, values may be cast to other types automatically upon comparison using this operator, this means values such as ‘5’ and 5will reported as equal.

The strict equality operator is === . The type of the value must be equal for this to evaluate to true, '5' === 5 would evaluate to false. 5 === 5 or '5' === '5' would evaluate to true .To avoid issues related to equality casting it’s recommended to always use triple equals for equality comparison.

Browser Support and Feature Detection

A large number of issues can come about when users open your website in an old browser or simply one you haven’t tested with. These issues could be in the form of rendering abnormalities (or worse, malfunctioning code) which causes your webpage to not work at all.

One way to avoid issues such as these is to make less assumptions about the capabilities of the browsers clients may use. This can be done by feature checking. A library such as Modernizr can help you determine whether or not a browser has the features you wish to utilize. You can then write fallback methods for the cases where features are not supported so users get at best a reimplementation with other technology or in the worst case a tidy explanation about why something isn’t supported.

Another way to avoid issues pertain

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: JavaJavaScript
分页:12
转载请注明
本文标题:Tips and Tricks for Debugging Client-side JavaScript
本站链接:http://www.codesec.net/view/483007.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(39)