最专业的八方代购网站源码!

资讯热点
10个JavaScript常见错误和修复

发布时间:2022-7-14 分类: 电商动态

如今,代购源码网站几乎使用了100%的JavaScript。 JavaScript似乎是一种非常简单的语言,但事实并非如此。它有很多容易被误解的细节。如果你不注意,它将导致错误。

 1. 错误的对this进行引用

在闭包或回调中,this关键字的范围很容易出错。例如:

Game.prototype.restart=function(){

this.clearLocalStorage();

This.timer=setTimeout(function(){

this.clearBoard(); //这指的是哪里?

},0);

};

如果您执行上面的代码,我们会看到一个错误:

未捕获的TypeError: undefined不是函数

出错的原因是当你调用setTimeout函数时,实际上是在调用window.setTimeout()。在setTimeout中传递的匿名函数位于窗口环境中,因此它指向窗口,但窗口没有clearBoard方法。

怎么解决?定义一个新的变量引用,指向Game对象的this对象,然后就可以使用它了。

Game.prototype.restart=function(){

this.clearLocalStorage();

Var self=this; //将此指向的对象绑定到self

This.timer=setTimeout(function(){

self.clearBoard();

},0);

};

或者使用bind()函数:

Game.prototype.restart=function(){

this.clearLocalStorage();

This.timer=setTimeout(this.reset.bind(this),0); //绑定到'this'

};

Game.prototype.reset=function(){

this.clearBoard(); //这里的引用是正确的

};

 2. 和块作用域(block scope)有关的BUG

在大多数编程语言中,每个功能块都有一个单独的新范围,但不是在JavaScript中。例如:

对于(var i=0; i< 10; i ++){

/* ... */

}

CONSOLE.LOG(ⅰ); //会输出什么?

通常在这种情况下,调用console.log()将输出undefined或错误。但是,这里将有10个输出。在JavaScript中,即使for循环结束,变量i仍然存在并且记录最后一个值。一些开发人员会忘记这一点,然后导致许多错误。我们可以使用let代替for来消除这个问题。

 3. 内存泄漏

您需要监视内存使用情况,因为很难避免泄漏。内存泄漏可能是由对不存在的对象或循环引用的引用引起的。

如何避免:关注对象的可达性。

可访问的对象:

可以在现有调用堆栈中的任何位置访问的对象

全局对象

当可以通过引用访问对象时,它将保存在内存中。浏览器的垃圾收集器仅回收那些不可访问的对象。

 4. 混淆的相等判断

JavaScript会自动将布尔环境中的所有变量类型转换为布尔类型,但可能会导致错误。例如:

//都是真的

Console.log(false=='0');

Console.log(null==undefined);

CONSOLE.LOG(”'==0);

Console.log(''==0);

//注意:以下两个也是

如果({})//…

如果([])//…

{}和[]都是对象,它们都被转换为true。为了防止错误,建议使用===和!==进行比较,因为类型转换不是隐式完成的。

 5. 低效的DOM操作

在JavaScript中,您可以轻松地操作DOM(添加,修改和删除),但开发人员往往操作效率低下。这可能导致错误,因为这些操作计算量很大。要解决此问题,如果需要操作多个DOM元素,建议使用Document Fragment。

广告:你的在线代码真的没有BUG吗?欢迎免费使用Fundebug!我们可以帮您找到错误!

 6. 在for循环中错误的定义函数

例如:

Var elements=document.getElementsByTagName('input');

Var n=elements.length; //假设我们有10个元素

对于(var i=0; i< n; i ++){

Elements [i] .onclick=function(){

Console.log('元素编号'+ i);

};

}

如果我们有10个元素,点击任何元素将显示“ldquo;元素编号10”!因为在调用onclick时for循环已经结束,所以我都是10.

解决方案:

Var elements=document.getElementsByTagName('input');

Var n=elements.length; //假设有10个元素

Var makeHandler=function(num){//外部函数

返回函数(){//内部函数

Console.log('元素编号'+ num);

};

};

对于(var i=0; i< n; i ++){

Elements [i] .onclick=makeHandler(i + 1);

}

执行for循环时立即调用makeHandler,获取当前值i + 1并存储在变量num中。 makeHandler返回一个使用num变量的函数,该变量绑定到元素的click事件。

 7. 通过原型错误地继承

如果开发人员无法正确理解继承的原则,那么就可以编写带有错误的代码:

BaseObject=function(name){

如果(typeof name!=='undefined'){

This.name=name;

} else {

This.name='default'

}

};

Var firstObj=new BaseObject();

Var secondObj=new BaseObject('unique');

CONSOLE.LOG(firstObj.name); // - >输出'默认'

CONSOLE.LOG(secondObj.name); // - >输出'独特'

但是,如果我们执行以下操作:

删除secondObj.name;

然后:

CONSOLE.LOG(secondObj.name); // - >输出'undefined'

我们真正想要的结果是打印默认名称。

BaseObject=function(name){

如果(typeof name!=='undefined'){

This.name=name;

}

};

BaseObject.prototype.name='default';

每个BaseObject都继承name属性,默认值为default。此时,如果删除了secondObj的name属性,则原型链接将返回正确的默认值。

Var thirdObj=new BaseObject('unique');

CONSOLE.LOG(thirdObj.name); // - >输出'独特'

删除thirdObj.name;

CONSOLE.LOG(thirdObj.name); // - >输出'默认'

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

让我们实现一个简单的构造函数来创建一个对象:

Var MyObject=function(){}

MyObject.prototype.whoAmI=function(){

Console.log(这==window?'window':'MyObj');

};

Var obj=new MyObject();

为了便于使用,我们将变量whoAmI定义为引用obj.whoAmI:

Var whoAmI=obj.whoAmI;

打印出来看看:

CONSOLE.LOG(WHOAMI);

控制台将输出:

函数(){

Console.log(这==window?'window':'MyObj');

}

现在让我们比较两个调用之间的差异:

obj.whoAmI(); //输出'MyObj'(符合预期)

我是谁(); //输出'window'(实际输出窗口)

当我们将obj.whoAmI分配给whoAmI时,新变量whoAmI是全局定义的,所以这指向全局窗口,而不是MyObj。如果我们真的想要获得对MyObj函数的引用,我们需要在其范围之内。

Var MyObject=function(){}

MyObject.prototype.whoAmI=function(){

Console.log(这==window?'window':'MyObj');

};

Var obj=new MyObject();

Obj.w=obj.whoAmI; //仍然在obj的范围内

obj.whoAmI(); //输出'MyObj'

Obj.w(); //输出'MyObj'

 9. setTimeout/setInterval函数第一个参数误用字符串

如果将字符串作为setTimeout/setTimeInterval,它将被传递给函数构造函数,并将构建一个新函数。这个过程缓慢而且效率低下并导致错误。

Var hello=function(){

Console.log('hello,fundebug!');

}

setTimeout('hello',1000);

一个很好的选择是将函数作为参数传递:

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

setTimeout(function(){//传入一个匿名函数

的LogMessage(msgValue);

},1000);

 10. 未能成功使用strict mode

使用严格模型会增加许多限制,以增强安全性并防止发生某些错误。如果您不使用严格模式,那么您就相当于拥有一个强大的帮助器来帮助您避免错误:

更容易调试

避免意外定义不应定义的全局变量

避免这种隐式转换

避免重用属性名称或参数值

Eval()更安全

无效的删除使用会自动抛出错误

版权声明:

转载时请注明作者的Fundebug和本文的地址:

https://blog.fundebug.com/2017/11/15/top_10_bugs_and_fixing_method/

« 人脸识别技术的发展与实用解决方案的设计 | 新鲜出炉!用户体验设计趋势2018年(下) »