JavaScript学习笔记:刻舟求剑新编

540 阅读4分钟

楚人有涉江者,其剑自舟中坠于水,遽契其舟曰:“是吾剑之所从坠。”舟止,从其所契者入水求之。舟已行矣,而剑不行,求剑若此,不亦惑乎!(战国·吕不韦《吕氏春秋·察今》)

这个故事在中国可谓家喻户晓,文中的楚人正是不会用发展的眼光来看待事物,才会贻笑大方。而刚学编程的新手在学习函数时经常会犯类似的错误。 让我们用几个例子才看看新手程序员容易犯迷糊的地方。

刻舟求剑

刻舟求剑

第1场 第1次

let a = 1  
//楚人的铁剑掉进了水里,他连忙拿出匕首在船上刻下一个记号。
function fn(){
    console.log(a)
}  //楚人大喊:我要去捞剑了!
//船夫:……
//楚人:怎么没有反应?我再喊一次。
function fn(){
    console.log(a)
}  //楚人大喊:我要去捞剑了!
//船夫:……
//楚人:咦?奇怪,我都喊了两次了。为嘛我的剑还没有上来?
//船夫:声音喊得那么大,你TM倒是跳啊!光喊有啥用?
//导演:咔!

qwxying:因为函数 fn 只是被声明了,而没有调用,所以不会执行。

若想要执行该函数,需要再加上一行代码,如下:

let a = 1  //银剑(1)掉水里了,做个记号。
function fn(){
    console.log(a)
}  //大喊:我要去捞剑了!
fn()  //跳水去捞剑,捞出银剑(1)。

第2场 第1次

/*次日,楚人佩了一柄铁剑,又要渡江,刚好又是昨天的船夫。*/
let a = 1 
/**楚人上船后,发现了昨天做的记号,
*道:这不是我昨天刻下的记号吗?
*今天我要把昨天掉的银剑捞起来。**/
function fn(){
    console.log(a)
}  //楚人大喊:我要去捞剑了!
a = 2  
/**刚刚说完话脱下外衣,
*却没发现铁剑(2)也从同样的位置掉进水里了。**/
fn()  /*跳水去捞剑*/
/*船夫:……*/
/**半晌,楚人从拿着铁剑(2)从河里出来了,
*哭丧着脸,道:再也找不回我的银剑了~**/
/*导演:咔!*/

qwxying:前面的 let a = 1 只是对函数要用到的变量做了一个声明,并不代表函数执行时该变量的值为其初始值。

COPY风云 之 职场小白的日常

小白的日常

第1场 第1次

年底快到了,职场新人小白正在写年终总结。

组里有7个人,小白来得最晚,所以他的工号是6。

员工0 是小白最好的朋友,每次写报告总结什么的,都会给默认给 员工0 copy一份

组里的其他人(1,2,3,4,5)看小白在写总结了,挨个过来说,小白总结写得不错嘛!加油!

对了,别忘了写完了发一份到我邮箱,给我参考参考,谢了哈,我要去摸鱼做报表了~

看好你哟


let i = 0  /**给默认给 员工0 copy一份**/
for( i = 0; i<6; ++i){
/**组员(0,1,2,3,4,5)依次让小白写完后给他发一份copy。**/
  setTimeout(()=>{
    console.log("这是给员工"+i+"的总结")
  },0)
}

可以看到,执行结果为打印了6次员工6的总结。

公开抄袭

qwxying:setTimeout会让小白在备忘录上记下一笔,在当前的事情处理完之后,再来执行备忘录上的事情。

第2场 第1次

上次写总结小组copy被BOSS发现了,狠狠地批评了一顿。

并要求每人写3000字的检讨。

小白痛定思痛,一气呵成写完了检讨。

这次其他人再也不敢大肆copy了,却还是不想自己写。

于是便在()里面用let“私信”小白,你把写好的文章发一段给我,其他的我自己编。

for(let i = 0; i<6; i++){  //let私信
  setTimeout(()=>{
    console.log("这是给员工"+i+"的检讨")
  },0)
}

可以看到,最终结果为每个员工的检讨副本都不一样。

私信检讨

qwxying:可以简单地理解为,此处的let有一个隐藏作用域,相当于 同事i 都是悄悄地告诉小白要做什么事情,而小白将每个 同事i 交代的事都记在了【单独】的备忘录上,所以得出的结果是不同的。

第n场 第n次

小白在之后的工作中与同事通力配合,又发现了几种新的方式得到不同的copy。

  1. 立即执行函数
let i 
for(i = 0; i<6; i++){
  !function(j){
      setTimeout(()=>{
        console.log(j)
      },0)
  }(i)
}
  1. 利用setTimeout的第三个参数,将i传进去
let i
for(i = 0; i<6; i++){
    setTimeout((value)=>{
      console.log(value)
    },0,i)
}
  1. 利用const关键字
let i
for(i = 0; i<6; i++){
    const x = i
    setTimeout(()=>{
      console.log(x)
    })
}

以上三种方式的不再赘述,相信年轻的樵夫哟,你能够看明白。

参考链接