13个JavaScript事不关己BUG及修复方法

作者:分分快三计划

3. 内存泄漏

您必要监察和控制内部存款和储蓄器使用量,因为走漏很难幸免。内部存款和储蓄器败露大概出于援引不设有的对象或则循环引用导致。

  • 如何幸免:关怀对象的可访谈性(reachability)。
  • 可访问的对象:
    • 幸存的call stack任何地点能够访谈的对象
    • 全局对象

当一个指标足以经过引用访谈到,那么会在内部存款和储蓄器中保存。浏览器的废料回笼器仅仅会把那三个不可访谈的靶子回笼。

10. 未能得逞选拔strict mode

动用strict model会追加非常多范围标准来拉长平安和防卫有些错误的产出,假设不行使strict mode,你就一定于少了三个精明能干的助理帮你制止不当:

  • 越是轻易debug
  • 制止非常大心定义了不该定义的全局变量
  • 幸免this隐式转变
  • 幸免属性名字或则参数值的重复使用
  • eval()越发安全
  • 无效地使用delete会自动抛出荒谬

图片 1

版权证明:
转发时请评释作者Fundebug以至本文地址:
https://blog.fundebug.com/2017/11/15/top_10_bugs_and_fixing_method/

2. 和块效能域(block scope)有关的BUG

在超越二分之一程序语言中,每叁个函数块都有一个独自的新的效率域,但是在JavaScript中并非。比方:

for (var i = 0; i < 10; i ) {
/* ... */
}
console.log(i); // 会输出什么呢?

通常说来在此种处境下,调用console.log()会输出undefined或则报错。不过呢,这里会输出10。在JavaScript中,纵然for循环已经完毕,变量i长久以来存在,并且记下最终的值。有个别开垦者会遗忘那或多或少,然后引致众多bug。我们能够行使let而不是for来杜绝那生机勃勃题目。

3. 内部存款和储蓄器泄漏

你必要监察和控制内部存款和储蓄器使用量,因为败露很难幸免。内部存款和储蓄器走漏或许出于引用海市蜃楼的靶子或则循环引用导致。

  • 怎么样制止:关切对象的可访谈性(reachability)。
  • 可访谈的靶子:
    • 幸存的call stack任何岗位能够访谈的指标
    • 大局对象

当多少个对象能够通过援用访谈到,那么会在内存中保留。浏览器的垃圾堆回笼器仅仅会把那个不可访谈的靶子回笼。

6. 在for循环中破绽超多的概念函数

举例:

var elements = document.getElementsByTagName('input');
var n = elements.length; // 假设我们有10个元素
for (var i = 0; i < n; i ) {
elements[i].onclick = function() {
console.log("元素编号#" i);
};
}

假若大家有11个因素,那么点击任何一个因素都会显得“成分编号#10”!因为在onclick被调用的时候,for循环已经达成,由此具备的i都以10。

解法:

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在for循环施行的时候立刻被调用,获取到日前的值i 1,並且存款和储蓄在变量num中。makeHandler回到三个函数使用num变量,该函数被绑定到成分的点击事件。

5. 低效的DOM操作

在JavaScript中,你能够轻易操作DOM(增添、改正和删除),可是开垦者往往很没用地去操作。这会诱致bug现身,因为那么些操作特别费用总计财富。为了消除那么些标题,推荐使用文书档案碎片(Document Fragment),要是您必要操作多个DOM成分。

广告: 您的线上代码真的没有BUG吗?款待无需付费应用Fundebug!我们得以协理您第有的时候间开采BUG!

7. 透过原型错误地持续

开采者要是没能正确精晓继承的准绳,那么就大概写出有bug的代码:

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'

而是,假诺大家做如下操作:

delete secondObj.name;

那么:

console.log(secondObj.name); // -> 输出'undefined'

 

而笔者辈实际上想要的结果是打字与印刷私下认可的name。

BaseObject = function (name) {
if(typeof name !== "undefined") {
this.name = name;
}
};
 
BaseObject.prototype.name = 'default';

 

每一个BaseObject都继承name属性,而且默许值为default。那个时候假如secondObjname质量被去除掉,通过原型链查找会重临正确的暗中同意值。

var thirdObj = new BaseObject('unique');
console.log(thirdObj.name); // -> 输出'unique'
 
delete thirdObj.name;
console.log(thirdObj.name); // -> 输出'default'

4. 歪曲的相当于决断

JavaScript自动将具有在布尔情形下的变量类型转变为布尔类型,可是或者导致bug。比如:

// 所有都是true
console.log(false == '0');
console.log(null == undefined);
console.log(" trn" == 0);
console.log('' == 0);

// 注意:下面两个也是
if ({}) // …
if ([]) // …

{}[]都以指标,他们都会被转变为true。为了防止bug现身,推荐使用===!==来做比较,因为不会隐式做类型转变。

5. 低效的DOM操作

在JavaScript中,你能够轻巧操作DOM(加多、改正和删除),可是开采者往往很没用地去操作。那会引致bug现身,因为这个操作拾分费用总括能源。为了减轻这一个主题材料,推荐应用文书档案碎片(Document Fragment),假令你要求操作四个DOM元素。

 

  • 原文: Top 10 bugs and their bug fixing
  • 译者: Fundebug

10. 无法得逞采取strict mode

运用strict model会加多非常多约束规范来加强平安定协调防御某个错误的面世,假设不利用strict mode,你就一定于少了贰个得力的帮手帮你制止不当:

  • 尤为便于debug
  • 幸免极大心定义了不应当定义的全局变量
  • 制止this隐式调换
  • 幸免属性名字或则参数值的重复使用
  • eval()尤其安全
  • 无效地使用delete会自动抛出错误

2. 和块成效域(block scope)有关的BUG

在大好多程序语言中,每贰个函数块都有八个单独的新的功能域,但是在JavaScript中并非。举例:

for (var i = 0; i < 10; i  ) {
  /* ... */
}
console.log(i);  // 会输出什么呢?

见惯不惊在此种状态下,调用console.log()会输出undefined或则报错。但是呢,这里会输出10。在JavaScript中,固然for循环已经竣事,变量i反之亦然存在,而且记录最终的值。有个别开辟者会遗忘那或多或少,然后导致众多bug。大家能够动用let而不是for来杜绝那少年老成标题。

1. 不当的对this实行引用

在闭包或则回调中,this重大字的效率域比较轻松弄错。比如:

Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(function() {
this.clearBoard(); // 此处this指的是?
}, 0);
};

 

意气风发经施行下面的代码,我们拜谒到报错:

Uncaught TypeError: undefined is not a function

 

出错的原因在于:当您调用setTimeout函数,你其实调用的是window.setTimeout()。在setTimeout中盛传的无名氏函数是在window本条指标条件下,所以this是指向window,但是window并没有clearBoard方法。

怎么消除吗?定义新的变量援用指向Game对象的this,然后就可以运用啊。

Game.prototype.restart = function () {
this.clearLocalStorage();
var self = this; // 将this指向的对象绑定到self
this.timer = setTimeout(function(){
self.clearBoard();
}, 0);
};

 

或则使用bind()函数:

Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(this.reset.bind(this), 0); // bind to 'this'
};
 
Game.prototype.reset = function(){
this.clearBoard(); // 此处this的引用正确
};

 还大概有部分JavaScript中错误的正确管理方式,招待点击参谋阅读。

8. 实例方法中的无效援引

我们来兑现三个大致的构造函数用来创设对象:

var MyObject = function() {}

MyObject.prototype.whoAmI = function() {
    console.log(this === window ? "window" : "MyObj");
};

var obj = new MyObject();

为了使用方便,我们定义变量whoAmI来引用obj.whoAmI

var whoAmI = obj.whoAmI;

打印出来看看:

console.log(whoAmI);

决定台会输出:

function () {
    console.log(this === window ? "window" : "MyObj");
}

近日我们来相比一下多头调用的区分:

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"

目前网址大致百分百运用JavaScript。JavaScript看上去是一门十三分粗略的言语,然则谜底并不这么。它有过多轻易被弄错的细节,一不注意就形成BUG。

为了保障可读性,本文接纳意译而非直译。此外,本文版权归最早的著小编全体,翻译仅用于学习。

8. 实例方法中的无效援用

大家来落到实处二个简练的构造函数用来创立对象:

var MyObject = function() {}
 
MyObject.prototype.whoAmI = function() {
console.log(this === window ? "window" : "MyObj");
};
 
var obj = new MyObject();

为了使用方便,大家定义变量whoAmI来引用obj.whoAmI

var whoAmI = obj.whoAmI;

 

打字与印刷出来看看:

console.log(whoAmI);

 

调节台会输出:

function () {
console.log(this === window ? "window" : "MyObj");
}

 

前段时间我们来对待一下双边调用的分别:

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"

今后网址大概百分百应用JavaScript。JavaScript看上去是一门十一分粗略的语言,不过事实并不那样。它有成都百货上千便于被弄错的内情,一不注意就导致BUG。

4. 歪曲的对等判别

JavaScript自动将全数在布尔处境下的变量类型转变为布尔类型,但是或者变成bug。例如:

// 所有都是true
console.log(false == '0');
console.log(null == undefined);
console.log(" trn" == 0);
console.log('' == 0);
 
// 注意:下面两个也是
if ({}) // …
if ([]) // …

{}13个JavaScript事不关己BUG及修复方法。和[]都是指标,他们都会被调换为true。为了防守bug现身,推荐使用===!==来做相比较,因为不会隐式做类型转变。

1. 谬误的对this举行援引

在闭包或则回调中,this13个JavaScript事不关己BUG及修复方法。主要字的成效域非常轻巧弄错。比方:

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(function() {
    this.clearBoard();    // 此处this指的是?
  }, 0);
};

只要实施下面的代码,大家会看见报错:

Uncaught TypeError: undefined is not a function

一念之差的原因在于:当你调用setTimeout函数,你实在调用的是window.setTimeout()。在setTimeout中传播的无名函数是在window这些目的条件下,所以this是指向window,但是window并没有clearBoard方法。

如何缓和吧?定义新的变量引用指向Game对象的this,然后就足以动用啊。

Game.prototype.restart = function () {
  this.clearLocalStorage();
  var self = this;   // 将this指向的对象绑定到self
  this.timer = setTimeout(function(){
    self.clearBoard();
  }, 0);
};

或则使用bind()函数:

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(this.reset.bind(this), 0);  // bind to 'this'
};

Game.prototype.reset = function(){
    this.clearBoard();    // 此处this的引用正确
};

                                                    图片 2

7. 经过原型错误地再三再四

开采者假诺未能正确驾驭世袭的原理,那么就只怕写出有bug的代码:

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'

只是,倘若大家做如下操作:

delete secondObj.name;

那么:

console.log(secondObj.name); // -> 输出'undefined'

而大家实际想要的结果是打字与印刷私下认可的name。

BaseObject = function (name) {
    if(typeof name !== "undefined") {
        this.name = name;
    }
};

BaseObject.prototype.name = 'default';

每一个BaseObject都继承name质量,并且暗中同意值为default。那时候要是secondObjname本性被剔除掉,通过原型链查找会再次回到正确的暗许值。

var thirdObj = new BaseObject('unique');
console.log(thirdObj.name);  // -> 输出'unique'

delete thirdObj.name;
console.log(thirdObj.name);  // -> 输出'default'

9. setTimeout/setInterval函数首先个参数误用字符串

假定你将叁个字符串作为setTimeout/setTimeInterval,它会被传给函数构造函数并塑造四个新的函数。该操作流程相当慢况兼不算,并引致bug现身。

var hello = function(){
console.log("hello, fundebug !");
}
setTimeout("hello", 1000);

一个好的代表方式正是传播函数作为参数:

setInterval(logTime, 1000); // 将logTime函数传入
 
setTimeout(function() { // 传入一个匿名函数
logMessage(msgValue);
}, 1000);

9. setTimeout/setInterval函数率先个参数误用字符串

借使您将二个字符串作为setTimeout/setTimeInterval,它会被传给函数构造函数并营造三个新的函数。该操作流程超慢并且不算,并变成bug出现。

var hello = function(){
  console.log("hello, fundebug !");
}
setTimeout("hello", 1000);

三个好的取代格局正是流传函数作为参数:

setInterval(logTime, 1000);   // 将logTime函数传入

setTimeout(function() {       // 传入一个匿名函数
    logMessage(msgValue);     
  }, 1000);

译者按: JavaScript语言设计太灵活,用起来难免要多加小心掉进坑里面。

6. 在for循环中错误的概念函数

举例:

var elements = document.getElementsByTagName('input');
var n = elements.length;    // 假设我们有10个元素
for (var i = 0; i < n; i  ) {
    elements[i].onclick = function() {
        console.log("元素编号#"   i);
    };
}

假设我们有拾叁个因素,那么点击任何三个要素都会来得“成分编号#10”!因为在onclick被调用的时候,for循环已经告竣,由此有所的i都以10。

解法:

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在for循环试行的时候立即被调用,获取到当前的值i 1,何况存款和储蓄在变量num中。makeHandler归来二个函数使用num变量,该函数被绑定到成分的点击事件。

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 Fundebug 博客