一不小心就会犯的错(js篇)

平凡无比的重复劳动也经常会发生一些匪夷所思的现象,发生的原因可能只是因为一个小疏忽,可能只是使用场景的改变,但是再平凡的代码,也会产生让你耗费大量时间才解决的问题。本篇就记录下这些细节,少走些弯路。长期更新,有人补充就更好啦。(文中的$代表jQuery,原谅我还做着jQuery项目= =)

1、清除定时器 clearTimeout

经常会维护一个变量,来控制定时器。

let timer = setTimeout(()=>{
  alert('我是定时器')},1000)
clearTimeout(timer);

上面的代码是不会弹出任何东西的,因为定时器被你清除了。那么这样呢

let timer = setTimeout(()=>{
  alert('我是定时器')
},1000)
timer =  setTimeout(()=>{
  alert('我还是定时器')
},1000);
clearTimeout(timer);

弹出了‘我是定时器’。因为起了2个定时器,clearTimeout是针对定时器的ID来工作,而此时的ID已经指向第二个定时器,所以无法把第一个定时器清除。
有人会有疑问,谁会这么傻,起两个定时器,这不是活该吗?
实战中还是很有可能会发生的,毕竟往往调用别人的函数,很容易一不小心起了两个定时器。比如有人这么写了个函数

let timer = null;
function showLoading(flag,time=10000){ //显示遮罩的函数
  if(flag){
    $('#load').show(); //显示遮罩
    timer = setTimeout(()=>{  //显示一定时间后隐藏遮罩
      $('#load').hide();
    },timer)
  }else{
     $('#load').hide();  //隐藏遮罩并去除定时器
    clearTimeout(timer);
  }
}

该函数的目的是显示遮罩,并且可以控制显示时间。
如果调用一次showLoading(true,30000)后在没有调用showLoading(false)的情况下再调用了一次,会发现第二次可能不到30S遮罩就消失了,原因就是起了两个定时器,而第一个定时器把你的遮罩取消了。
所以实际开发中起定时器前一般要先清除,这样别人就算调了两次你的函数,也不会有问题,写公共函数的同学尤其注意了

let timer = null;
function showLoading(flag,time=10000){ //显示遮罩的函数
  if(flag){
    $('#load').show(); //显示遮罩
    if(timer !== null){  //判断是否有定时器
      clearTimeout(timer);
    }
    timer = setTimeout(()=>{  //显示10S后隐藏遮罩
      $('#load').hide();
    },timer)
  }else{
     $('#load').hide();  //隐藏遮罩并去除定时器
    clearTimeout(timer);
    timer = null;  //清除后变为null,表示该定时器已经被清除
  }
}

靠timer是否等于null来判断是否有定时器在工作

2、call,apply

非常需要注意,call和apply后面需要先写一个对象,代表谁来调用这个函数,之后才是函数的参数,千万不能把上下文对象漏了,否则后果很严重。

function add(a,b){
  return a+b;
}
add.call(null,2,3);  //5
add.call(2,3);  //NaN

像这种情况还行,错误很明显。如果是在处理延迟对象的时候漏掉了。

//defArr是用来存放延迟对象的数组
$.when.apply(defArr).done(function(){}); //此时相当于$.when().done()

done的函数就起不到回调函数作用,它会马上执行,不等待延迟对象的返回结果。有时这错误还很难发现,所以要特别注意。赶紧检查下你们代码中有没有漏掉第一个参数的地方。

3、removeEventListener

document.body.addEventListener('click',function(){
  alert(1);
})
document.body.removeEventListener('click',function(){
  alert(1);
})

此时点击body还是会弹出1。因为移除时传入的参数必须与添加处理程序时使用的参数完全相同。两个匿名函数,虽然作用一样,但是却不相等。所以要这样

var ev = function(){
  alert(1);
}
document.body.addEventListener('click',ev);
document.body.removeEventListener('click',ev);

习惯jquery的用户是不是惊呆了。赶紧记住!

4、活用Deferred.then

这个点针对jquery用户,当然也可以套用到ES6 的Promise上。
then不仅可以简写done和fail,同时还有个更强大的功能,就是返回一个新的Deferred对象。
比如,有这么一个库函数

function readFile(){
  return $.Deferred((def)=>{
    setTimeout(()=>{
      def.resolve({
        params:1
      })
    },1000); 
  })
}

新手使用readFile的时候可能会这样写

function test(){
   return $.Deferred((def)=>{
     readFile().done(json=>{
       def.resolve(json.params)
    }) 
  }) 
}
test().done(json=>{
  alert(json);
})

没毛病,的确处理了readFile的返回结果。但是额外在readFile外面包了一层,多了一层嵌套。如果使用then的话会简洁很多

function test(){
     return readFile().then(json=>{  //注意这里是then不是done哦
       return json.params;
    }) 
}
test().done(json=>{
  alert(json);
})

then会返回一个新的Deferred对象,活用它代码会简洁很多。如果不是很清楚,可以去百度下jquery done和then的区别,这里不做详细解释。
ES6的Promise也适用,不用每次都去调用Promise构造函数生成新的Promise,而是选择使用then。

5、sort()排序

let arr = [3,2,1];
arr.sort(); //1,2,3

sort()函数按升序排列数组项。但是它会调用每个数组项的toString()方法,然后比较得到的字符串,所以如果出现两位数就达不到效果了。

let arr = [3,2,13];
arr.sort(); //13,2,3

13跑到最前面了。因为"13"<"2"。
所以正确的写法是在参数里写上判断函数。
有人可能会这么写

let arr = [3,2,1];
arr.sort((a,b)=> a>b); //1,2,3

数组里全是数字的情况可以胜用。但是如果数组里的元素是字符串就会失败。

let arr = ["3","2","13"];
arr.sort((a,b)=> a>b); //"13","2","3"

因为有很多情况,期望是数字的值,实际上是字符串。比如从input中获取值。所以以下代码是最靠谱的

let arr = ["3","2","13"];
arr.sort((a,b)=> a-b); //"2","3","13"

通过a-b来控制升序。"13"<"2"但是"13" - "2" > 0

6、setTimeout和箭头函数

大家都知道箭头函数是可以将this绑定为定义时的对象,但是我在Vue开发中却遇到了个匪夷所思的现象,this还是指向了window。不信邪的我赶紧写个测试代码压压惊

let a = 1;
let obj = {
  a:2,
  foo(){
    setTimeout(()=>{
      console.log(this.a);
    },2000)
  }
}
obj.foo(); //2

舒了口气,看来没学错。
再仔细看看,发现定时器实际生效时,组件被销毁了,于是加了个keep-alive,缓存组件,this终于成功指向了该组件。

未完待续。。。有错误的还望指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容