前兩天班級聚會,除了吃喝玩樂就是睡覺扯淡,甚是喜悅,真是獨樂樂不如眾樂樂啊。
PS:畢業的或即將畢業的有時間能聚就聚吧,畢了業以後屬於自己的時間能聚到一塊兒可就少太多了。
現在有點時間來看點東西總結些東西了,又因為前段時間片片斷斷地看了看JavaScript的函數部分,所以抽時間總結下函數的相關部分,當然,裡面有些部分都是自己的理解,如果有理解的不對的地方還請小夥伴們不吝指出。
這一節我結合自己的理解和小夥伴們聊一下函數宣告的宣告提前。
註:有的地方也叫函數宣告提升。翻譯的不一樣,意思一樣,大家懂就好。理解萬歲!
在聊函數宣告的宣告提前之前,有必要介紹下函數定義的幾種方法,大部分小夥伴們應該都不陌生。了解的或是不想了解的就痛快地一滾輪滾下去吧,不熟悉的或者想再熟悉一下的就放慢腳步起步走。
定義函數的方法
定義函數的方法主要有三種:
1.函數宣告(Function Declaration)
2.函數表達式Function Expression)
3.new Function建構子
其中,經常使用的是函數聲明和函數表達式的函數定義方法,這兩種方法有著很微妙的區別和聯繫,而且這兩種方法的使用也容易混淆,所以這篇文章主要總結下這兩種函數定義方法的相關知識點,當然本文的主題依然是關於函數提前的。
函數宣告的典型格式:
function functionName(arg1, arg2, ...){ <!-- function body --> }
函數表達式
•函數表達式的典型格式:
var variable=function(arg1, arg2, ...){ <!-- function body --> }
包含名稱(括弧,函數名)的函數表達式:
var variable=function functionName(arg1, arg2, ...){ <!-- function body --> }
像上面的帶有名稱的函數表達式可以用來遞歸:
var variable=function functionName(x){ if(x<=1) return 1; else return x*functionName(x); }
聲明提前
var聲明提前
小夥伴們應該都聽說過宣告提前的說法,我想在此再次重申一遍,因為宣告提前是函數宣告和函數表達式的一個重要區別,對於我們進一步理解這兩種函數定義方法有著重要的意義。
但是再說函數宣告提前之前呢,有必要說一下var宣告提前。
先給出var聲明提前的結論:
變數在宣告它們的腳本或函數中都是有定義的,變數宣告語句會被提前到腳本或函數的頂端。但是,變數初始化的操作還是在原來var語句的位置執行,在宣告語句之前變數的值是undefined。
上面的結論中可以總結出三個簡單的點:
1.變數宣告會提前到函數的頂端;
2.只是宣告被提前,初始化不提前,初始化還在原來初始化的位置進行初始化;
3.在宣告之前變數的值是undefined。
還是來例子實在:
var handsome='handsome'; function handsomeToUgly(){ alert(handsome); var handsome='ugly'; alert(handsome); } handsomeToUgly();
正確的輸出結果是:
先輸出undefined,然後輸出ugly。
錯誤的輸出結果是:
先輸出handsome,然後輸出ugly。
這裡正是變數宣告提前起到的作用。該handsome局部變量在整個函數體內都是有定義的,在函數體內的handsome變量壓住了,哦不對,是覆蓋住了同名的handsome全局變量,因為變量聲明提前,即var handsome被提前至函數的頂部,就是這個樣子:
var handsome='handsome'; function handsomeToUgly(){ var handsome; alert(handsome); var handsome='ugly'; alert(handsome); } handsomeToUgly();
所以說在alert(handsome)之前,已經有了var handsome聲明,由上面提到的
在宣告之前變數的值是undefined
所以第一個輸出undefined。
又因為上面提到的:
只是宣告被提前,初始化不提前,初始化還在原來初始化的位置進行初始化
所以第二個輸出ugly。
函數宣告提前
接下倆我們結合var宣告提前開始聊函數宣告的宣告提前。
函數宣告的宣告提前小夥伴應該很熟悉,舉個再熟悉不過的例子。
sayTruth();<!-- 函数声明 --> function sayTruth(){ alert('myvin is handsome.'); } sayTruth();<!-- 函数表达式 --> var sayTruth=function(){ alert('myvin is handsome.'); }
小伙伴们都知道,对于函数声明的函数定义方法,即上面的第一种函数调用方法是正确的,可以输出myvin is handsome.的真理,因为函数调用语句可以放在函数声明之后。而对于函数表达式的函数定义方法,即上面的第二种函数调用的方法是不能输出myvin is handsome.的正确结果的。
结合上面的myvin is handsome.例子,函数声明提前的结论似乎很好理解,不就是在使用函数声明的函数定义方法的时候,函数调用可以放在任意位置嘛。对啊,你说的很对啊,小伙伴,我都不知道怎么反驳你了。那就容我再扯几句。
从小伙伴所说的
不就是在使用函数声明的函数定义方法的时候,函数调用可以放在任意位置嘛
可以引出一点:
函数声明提前的时候,函数声明和函数体均提前了。
而且:
函数声明是在预执行期执行的,就是说函数声明是在浏览器准备执行代码的时候执行的。因为函数声明在预执行期被执行,所以到了执行期,函数声明就不再执行(人家都执行过了自然就不再执行了)。
上面是一点。
函数表达式为什么不能声明提前
我们再说一点:为什么函数表达式不能像函数声明那样进行函数声明提前呢?
辛亏我知道一点儿,否则真不知道我该怎么回答呢?
咳咳,按照我的理解给小伙伴们解释一下下:
我们上面说了var的声明提前,注意我上面提过的:
只是声明被提前,初始化不提前,初始化还在原来初始化的位置进行初始化
Ok,我们把函数表达式摆在这看看:
var variable=function(arg1, arg2, ...){ <!-- function body --> }
函数表达式就是把函数定义的方式写成表达式的方式(貌似是白说,但是这对于解释和理解为毛函数表达式不能函数声明提前具有良好的疗效),就是把一个函数对象赋值给一个变量,所以我们把函数表达式写成这个样子:
var varible=5看到这,也许小伙伴们会明白了,一个是把一个值赋值给一个变量,一个是把函数对象赋值给一个变量,所以对于函数表达式,变量赋值是不会提前的,即function(arg1, arg2, ...){bb673d5c66f2af4526aea043e376eb75}是不会提前的,所以函数定义并没有被执行,所以函数表达式不能像函数声明那样进行函数声明提前。
函数声明提前的实例分析
还是那句话,还是例子来的实在:
sayTruth(); if(1){ function sayTruth(){alert('myvin is handsome')}; } else{ function sayTruth(){alert('myvin is ugly')}; }
在浏览器不抛出错误的情况下(请自行测试相应的浏览器是否有抛出错误的情况,为啥我不测试?我能说我懒么。。。),浏览器的输出结果是输出myvin is ugly(我不愿承认,但是事实就是这样啊啊啊啊,难道道出了人丑就该多读书??????)。
为什么呢?当然是声明提前了。因为函数声明提前,所以函数声明会在代码执行前进行解析,执行顺序是这样的,先解析function sayTruth(){alert('myvin is handsome')},在解析function sayTruth(){alert('myvin is ugly')},覆盖了前面的函数声明,当我们调用sayTruth()函数的时候,也就是到了代码执行期间,声明会被忽略,所以自然会输出myvin is ugly(好残酷的现实。。。)。忘了的可以看上面说过的:
函数声明是在预执行期执行的,就是说函数声明是在浏览器准备执行代码的时候执行的。因为函数声明在预执行期被执行,所以到了执行期,函数声明就不再执行了(人家都执行过了自然就不再执行了)。
小了个结
关于函数声明的函数提前(提升)就聊到这里先,希望我的理解和扯淡能够对有需要的小伙伴有所帮助。
当然,实践出真知。对事物的了解、认知和运用还是在于多看多用多总结,记得有句名言,是讲声明和实践的:“动起来,为新的声明喝彩。”。
以上这篇浅析函数声明和函数表达式——函数声明的声明提前就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。