The design of the JavaScript language is too flexible, so you have to be careful about falling into pits when using it. The design of the JavaScript language is too flexible, so you have to be careful about falling into pits when using it. This article shares with you 10 common JavaScript BUGs and how to fix them. Almost 100% of websites today use JavaScript. JavaScript seems to be a very simple language, but this is not the case. It has a lot of details that are easy to get wrong, which can lead to bugs if you don't pay attention.
In closures or callbacks, the scope of the this
keyword is easy to get wrong. For example:
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(function() { this.clearBoard(); // 此处this指的是? }, 0); };
If you execute the above code, we will see an error:
Uncaught TypeError: undefined is not a function
The reason for the error is: when you call the setTimeout
function, you actually The call is window.setTimeout()
. The anonymous function passed in setTimeout
is in the object environment of window
, so this
points to window
, but window
does not have a clearBoard
method.
How to solve it? Define a new variable reference that points to this
of the Game
object, and then you can use it.
Game.prototype.restart = function () { this.clearLocalStorage(); var self = this; // 将this指向的对象绑定到self this.timer = setTimeout(function(){ self.clearBoard(); }, 0); };
Or use the bind()
function:
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); // bind to 'this' }; Game.prototype.reset = function(){ this.clearBoard(); // 此处this的引用正确 };
In most cases In programming languages, each function block has an independent new scope, but not in JavaScript. For example:
for (var i = 0; i < 10; i++) { /* ... */ } console.log(i); // 会输出什么呢?
Usually in this case, calling console.log()
will output undefined
or report an error. However, 10
will be output here. In JavaScript, even if the for loop has ended, the variable i
still exists and the last value is recorded. Some developers forget this, which leads to many bugs. We can use let
instead of for
to eliminate this problem.
You need to monitor memory usage because leaks are difficult to avoid. Memory leaks can occur due to references to non-existent objects or circular references.
How to avoid: Focus on the reachability of the object.
Accessible objects:
Objects accessible from anywhere in the existing call stack
Global Object
When an object can be accessed through a reference, it will be saved in memory. The browser's garbage collector will only reclaim objects that are inaccessible.
JavaScript automatically converts all variable types in Boolean environments to Boolean types, but this may lead to bugs. Example:
// 所有都是true console.log(false == '0'); console.log(null == undefined); console.log(" \t\r\n" == 0); console.log('' == 0); // 注意:下面两个也是 if ({}) // … if ([]) // …
{}
and []
are both objects, and they will be converted to true. In order to prevent bugs, it is recommended to use ===
and !==
for comparison, because type conversion will not be performed implicitly.
In JavaScript, you can easily operate the DOM (add, modify and delete), but developers often do it very inefficiently. This can lead to bugs because these operations are very computationally intensive. To solve this problem, it is recommended to use Document Fragment if you need to operate multiple DOM elements.
Advertisement: Is your online code really free of bugs? Welcome to use Fundebug for free! We can help you find BUGs as soon as possible!
Example:
var elements = document.getElementsByTagName('input'); var n = elements.length; // 假设我们有10个元素 for (var i = 0; i < n; i++) { elements[i].onclick = function() { console.log("元素编号#" + i); }; }
If We have 10 elements, so clicking on any element will display "Element Number #10"! Because when onclick
is called, the for loop has ended, so all i's are 10.
Solution:
var elements = document.getElementsByTagName('input'); var n = elements.length; // 假设有10个元素 var makeHandler = function(num) { // outer function return function() { // inner function console.log("元素编号##" + num); }; }; for (var i = 0; i < n; i++) { elements[i].onclick = makeHandler(i+1); }
makeHandler
is called immediately when the for loop is executed, obtains the current value i+1
, and stores it in in variable num
. makeHandler
Returns a function using the num
variable that is bound to the element's click event.
If developers do not correctly understand the principles of inheritance, they may write buggy code:
BaseObject = function(name) { if(typeof name !== "undefined") { this.name = name; } else { this.name = 'default' } }; var firstObj = new BaseObject(); var secondObj = new BaseObject('unique'); console.log(firstObj.name); // -> 输出'default' console.log(secondObj.name); // -> 输出'unique'
However, if We do the following:
delete secondObj.name;
Then:
console.log(secondObj.name); // -> 输出'undefined'
The result we actually want is to print the default name.
BaseObject = function (name) { if(typeof name !== "undefined") { this.name = name; } }; BaseObject.prototype.name = 'default';
Every BaseObject
inherits the name
attribute, and the default value is default
. At this time, if the name
attribute of secondObj
is deleted, searching through the prototype chain will return the correct default value.
var thirdObj = new BaseObject('unique'); console.log(thirdObj.name); // -> 输出'unique' delete thirdObj.name; console.log(thirdObj.name); // -> 输出'default'
Let’s implement a simple constructor to create objects:
var MyObject = function() {} MyObject.prototype.whoAmI = function() { console.log(this === window ? "window" : "MyObj"); }; var obj = new MyObject();
For ease of use, we define variableswhoAmI
to quote obj.whoAmI
:
var whoAmI = obj.whoAmI;
Print it out and see:
console.log(whoAmI);
The console will output:
function () { console.log(this === window ? "window" : "MyObj"); }
Now we Let’s compare the difference between the two calls:
obj.whoAmI(); // 输出"MyObj" (和期望一致) whoAmI(); // 输出"window" (竟然输出了window)
当我们把obj.whoAmI
赋值给whoAmI
的时候,这个新的变量whoAmI
是定义在全局下,因此this
指向全局的window
,而不是MyObj
。如果我们真的要获取对MyObj
的函数的引用,需要在其作用域下。
var MyObject = function() {} MyObject.prototype.whoAmI = function() { console.log(this === window ? "window" : "MyObj"); }; var obj = new MyObject(); obj.w = obj.whoAmI; // 任然在obj的作用域 obj.whoAmI(); // 输出"MyObj" obj.w(); // 输出"MyObj"
如果你将一个字符串作为setTimeout/setTimeInterval,它会被传给函数构造函数并构建一个新的函数。该操作流程很慢而且低效,并导致bug出现。
var hello = function(){ console.log("hello, fundebug !"); } setTimeout("hello", 1000);
一个好的替代方法就是传入函数作为参数:
setInterval(logTime, 1000); // 将logTime函数传入 setTimeout(function() { // 传入一个匿名函数 logMessage(msgValue); }, 1000);
使用strict model会增加很多限制条件来加强安全和防止某些错误的出现,如果不使用strict mode
,你就相当于少了一个得力的助手帮你避免错误:
更加容易debug
避免不小心定义了不该定义的全局变量
避免this隐式转换
避免属性名字或则参数值的重复使用
eval()更加安全
无效地使用delete会自动抛出错误
以上内容就是10个JavaScript常见BUG及修复方法,希望能帮助到大家。
相关推荐:
PHP中调试函数debug_backtrace的使用方法介绍
The above is the detailed content of 10 common JavaScript bugs and how to fix them. For more information, please follow other related articles on the PHP Chinese website!