“这小娃娃真是好大的口气,一口气说函数有七重关,老夫要好好品鉴一番。”尹曾琪目露精光,口气中带着一丝嘲讽,却也有一丝好奇。
林元青也被叶小凡的话吓了一跳,全场更是炸开了锅。
“这个叶小凡,说话还真是狂妄,什么函数七重关,我倒要看看他能够说出个什么来!”
罗丹面色凝重,眼睛更是一下不眨地盯着叶小凡。叶小凡也愣了一下,这实在是怨不得叶小凡,这函数七重关,可是叶老亲自教导自己的。在平时和叶老的交流中,叶小凡也早已习惯把“函数七重关”挂在嘴边。谁知道,自己把“函数七重关”一讲,会引起这么大的轰动!
“好,叶小凡,你就说说,你所谓的‘函数七重关’究竟是什么吧。”林元青也微笑着摇了摇头,对叶小凡说道。
“是,弟子遵命。函数七重关的第一重关,自然指的是函数的定义。”叶小凡小声说道。
“函数的定义需要用到function关键字,定义函数的语法方才这位师兄已经讲过了,我不再赘述。只是需要提一下,除了刚才那位师兄提到的定义函数的方法,其实还有另一种方法。”说着,叶小凡随手打出了一段代码。
“这是第一种定义函数的方法,也是最常用的方法。哦,对了,里面的document.write方法表示用JavaScript向页面输出一段话。接下来,我再讲讲第二种方法。”说着,叶小凡又随手打出了一段代码。
“这便是第二种定义函数的方法了,和第一种方法有所不同,第二种定义函数的方法需要先定义一个变量,比如‘var a’,然后还是用function关键字定义一个函数,再把这个函数赋值给变量a。因为最后要赋值给变量a,因此这里在定义函数的时候就不需要加上函数的名字了,这就是其中的一个区别。用这种方法定义出来的函数,函数的名字就是变量的名字,也就是说,我要想调用这个函数,就要这样做。”
a();
“哗众取宠,这两种方法在本质上没什么区别,不都是一样吗?”对面的弟子对叶小凡的讲解嗤之以鼻。
“这自然是有区别的,刚才我讲了第一个区别,现在说第二个区别。第二个区别就体现在函数的调用上。”说着,叶小凡又随手打出了一段代码。
“这位师兄,你说我这段代码可以成功调用函数a吗?”
“你这不废话吗,当然可以了!”
“好,那师兄请看。”叶小凡开始执行代码。
Uncaught TypeError: a is not a function
众人看得真切,代码居然直接报错了!对面的弟子瞬间不说话了,场面一度有点尴尬。
“如果是用第一种方法定义的函数,把调用语句放在前面,则可以成功调用。”
代码运行后,成功在页面上打印出:This is My First Function!
众人一下子又炸开了锅,有的大弟子一脸的难以置信。就连尹曾琪也对叶小凡稍显关注,场外的罗丹面色则更加凝重。
“导致这种情况的原因是,如果是用第一种方法定义的函数,它会被提前加载,因此调用语句可以写在函数的定义之前,因为那个时候函数已经被加载完毕了。 而用第二种方式定义的函数是不会被提前加载的 。换句话说,必须要执行到函数定义的语句才会加载这个函数,正因为这个道理,刚才的代码才会直接报错。因为在调用a函数的时候,a函数还没有加载,强行调用一个不存在的函数自然是不被允许的!”
“接下来,我再举一个例子说明这个情况吧。”说着,叶小凡又随手打出了一段代码。
代码运行后的结果一如叶小凡所言,第一个a打印出来是undefined,表示未定义。第二个a打印出来就是具体的函数了,说明这个时候函数a已经被加载完毕!
“我有问题,为什么第一个a打印出来是undefined,而不是直接报错呢?”对面的弟子疑惑地问道,接着他又侃侃而谈:“我之前遇到过这种情况,就是引用一个从来没有被定义过的变量,得到的结果是直接报错的!比如这个。”
console.log(apple);
ReferenceError: apple is not defined
“看吧,这样写的话就直接报错了,因为我从来没有在任何地方定义过一个apple变量。你刚才调用了一个还未被加载的函数,为什么会打印出undefined而不是报错呢?”
“是啊,这是为什么呢?看看叶小凡怎么说。”场外又窃窃私语起来。
“你混淆了概念, 函数有没有被加载与变量有没有被定义是不同的事情 ,不要放在一起谈论。就比如说我刚才打的代码。”
“注意看,函数有没有被加载,可以看成function有没有被赋值给变量a。从代码上来看,自然是没有的。因为‘console.log’语句是写在‘var a =function(){’的前面啊,也就是说,当调用变量a的时候,变量a并没有被赋值。但是不管变量a有没有被赋予一个funciton函数,我就问你一个问题,a有没有定义?”
“额,这个,定义是定义了,可是它并没有被运行到啊!”对面的弟子一脸的不服气。
“这就要说到JavaScript代码的运行机制了。”叶小凡淡淡地说道,丝毫没有慌乱,因为在叶老给他灌输函数七重关的时候,他也有过一样的疑问。