函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
函數(shù)聲明:
function functionName(){
statement;
}// 無分號(hào)
functionName();
函數(shù)表達(dá)式:
var functionName = function(){
statement;
};// 有分號(hào)
functionName();
以上為兩者寫法的區(qū)別腺毫。由名稱可以看出 “函數(shù)表達(dá)式” 的實(shí)質(zhì)為表達(dá)式肯污,“函數(shù)聲明”則是使用
function
關(guān)鍵字聲明的一個(gè)函數(shù)掏熬,而它們執(zhí)行和調(diào)用的方法完全相同。-
兩者最大區(qū)別在于聲明前置的不同豁辉。如下:
fn("valley");
var fn = function (str){
console.log(str);// Uncaught TypeError: fn is not a function
}var fn = function (str){ console.log(str);// 輸出結(jié)果 valley }; fn("valley"); //使用函數(shù)表達(dá)式,聲明前置的規(guī)則和變量一樣把将!(具體參照下一題) ----------------------------------------------------------------------------- function fn(str){ console.log(str);// 輸出結(jié)果 valley } fn("valley"); //使用函數(shù)聲明的方式没酣,那么即使函數(shù)寫在最后也可以在前面語句調(diào)用,當(dāng)然前提是函數(shù)聲明部分已經(jīng)被下載到本地
注:推薦使用函數(shù)聲明被饿,不用表達(dá)式四康。ps:何必自造麻煩~(函數(shù)調(diào)用要有分號(hào)哦)
什么是變量的聲明前置?什么是函數(shù)的聲明前置
聲明前置是把該聲明的變量和函數(shù)提升到自身所在作用域的頂部狭握。
-
變量的聲明前置
先獲取所有被聲明的變量(僅變量名闪金,不包括其值),然后再逐行運(yùn)行论颅。這使得所有
變量的聲明被提前到作用域頂部哎垦,賦值保留在原地;而“函數(shù)表達(dá)式的聲明相當(dāng)于變量的聲明”恃疯,當(dāng)函數(shù)作為值賦給變量時(shí)只有變量“被提前”了(var functionName; 提前了)漏设,函數(shù)體并沒有“被提前”。
console.log(a);// undefined,未賦值
var a = 1;
console.log(a);// 1今妄,為變量a賦值等于1
console.log(b);// error,報(bào)錯(cuò)郑口。不存在
//以上代碼相當(dāng)于以下:
var a;
console.log(a);
a = 1;
console.log(a);
console.log(b);
-
函數(shù)的聲明前置
函數(shù)的聲明“整個(gè)”被提前,使函數(shù)在執(zhí)行任何代碼之前都可以訪問盾鳞。
a(1);// 有分號(hào)犬性,函數(shù)調(diào)用形式
function a(name){// name為占位符,形參
console.log(name);// 輸出結(jié)果 1
}
以上代碼相當(dāng)于以下:
function a(name){
console.log(name);// 輸出結(jié)果 1
}
a(1);
特別注意腾仅,若有同一名稱的變量和函數(shù)乒裆,則函數(shù)會(huì)覆蓋變量。
console.log(a);
function a(){ return;}// 控制臺(tái)a顯示為函數(shù)推励,證明聲明前置時(shí)鹤耍,函數(shù)會(huì)覆蓋同名的變量聲明。
var a;
arguments 是什么
簡(jiǎn)單說就是验辞,收集了函數(shù)中參數(shù)的一個(gè)類數(shù)組對(duì)象稿黄。
arguments可以打印出你所傳入的所有參數(shù)且以酷似數(shù)組的形式出現(xiàn)。
function sum(){
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum = sum + arguments[i];
}
}// 函數(shù)內(nèi)部,你可以使用arguments對(duì)象獲取到該函數(shù)的所有傳入?yún)?shù)
arguments作用:
可實(shí)現(xiàn)JS的類似函數(shù)重載的功能受神。
函數(shù)的重載怎樣實(shí)現(xiàn)抛猖?
重載是很多面向?qū)ο笳Z言實(shí)現(xiàn)多態(tài)的手段之一,在靜態(tài)語言中確定一個(gè)函數(shù)的手段是靠方法簽名——函數(shù)名+參數(shù)列表鼻听,也就是說相同名字的函數(shù)參數(shù)個(gè)數(shù)不同或者順序不同都被認(rèn)為是不同的函數(shù)财著,稱為函數(shù)重載。
在JavaScript中沒有函數(shù)重載的概念撑碴,函數(shù)通過名字確定唯一性撑教,參數(shù)不同也被認(rèn)為是相同的函數(shù),后面的覆蓋前面的醉拓。
function sum(){
console.log(arguments);
}
sum(1);
sum(1, 2, 3);/* js中的函數(shù)無傳統(tǒng)意義的重載 */
function sum(a, b){
return a + b;
}
function sum(a, b, c){
return a + b + c;
}
sum(1, 2);//出錯(cuò)
sum(1, 2, 3);/* 用arguemnts實(shí)現(xiàn)重載*/
function newSum(){
var sum = 0;
for(var i = 0; i< arguments.length; i++){
sum += arguments[i];
}
return sum;
}
立即執(zhí)行函數(shù)表達(dá)式是什么伟姐?有什么作用
立即調(diào)用函數(shù)表達(dá)式常見的有兩種寫法:
(function(){} ());
(function(){})();
立即調(diào)用函數(shù)表達(dá)式作用:
立即執(zhí)行函數(shù)可以將寫在函數(shù)體內(nèi)的語句直接執(zhí)行收苏。區(qū)別于普通語句,立即執(zhí)行函數(shù)內(nèi)的變量不會(huì)干擾函數(shù)體外愤兵,形成一個(gè)類似區(qū)塊的空間鹿霸。它能做到各模塊的低耦合,減少對(duì)全局作用域的污染秆乳,省去起函數(shù)名懦鼠。
知乎-立即調(diào)用的函數(shù)表達(dá)式
cnblogs-深入理解JavaScript系列
什么是函數(shù)的作用域鏈
在JavaScript中,函數(shù)也是對(duì)象屹堰,實(shí)際上肛冶,JavaScript里一切都是對(duì)象。函數(shù)對(duì)象和其它對(duì)象一樣扯键,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內(nèi)部屬性睦袖。其中一個(gè)內(nèi)部屬性是[[Scope]],由ECMA-262標(biāo)準(zhǔn)第三版定義荣刑,該內(nèi)部屬性包含了函數(shù)被創(chuàng)建的作用域中對(duì)象的集合馅笙,這個(gè)集合被稱為函數(shù)的作用域鏈,它決定了哪些數(shù)據(jù)能被函數(shù)訪問厉亏。
JavaScript 開發(fā)進(jìn)階:理解 JavaScript 作用域和作用域鏈
代碼練習(xí)
1.以下代碼輸出什么延蟹? (難度2)
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('hunger', 28, '男');
getInfo('hunger', 28);
getInfo('男');
輸出結(jié)果:
2.寫一個(gè)函數(shù),返回參數(shù)的平方和叶堆?如 (難度2)
function sumOfSquares(){
}
sumOfSquares(2,3,4);// 29
sumOfSquares(1,3);// 10
3.如下代碼的輸出?為什么 (難度1)
console.log(a);
var a = 1;// undefined
console.log(b);// "error"
結(jié)果
原因
以上代碼還可以寫成如下:
var a;// 變量聲明前置
console.log(a);// 變量a已被聲明斥杜,但還未被解析到賦值部分虱颗,所以u(píng)ndefined
a = 1;
console.log(b)// 變量b未被聲明,故解析報(bào)錯(cuò)"error"
4.如下代碼的輸出蔗喂?為什么 (難度1)
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
結(jié)果
原因
以上代碼相當(dāng)于:
function sayName(name){
console.log('hello ', name);
}// “函數(shù)聲明格式”的函數(shù)忘渔,“整個(gè)”被提前
var sayAge;// “函數(shù)表達(dá)式格式”的函數(shù),只有“變量”(var functionName;)被提前了缰儿,函數(shù)體并沒有“被提前”
sayName('world');// 調(diào)用畦粮,函數(shù)體正常計(jì)算出結(jié)果
sayAge(10);// 調(diào)用,該“變量”非函數(shù)乖阵,出錯(cuò)
var sayAge = function(age){
console.log(age);
};
5.如下代碼的輸出宣赔?為什么 (難度2)
function fn(){
}
var fn = 3;
console.log(fn);// 結(jié)果為3
分步解析:
-
步驟1
var fn;// 變量聲明前置 //function fn(){ //} //fn = 3; console.log(fn);
-
步驟2
var fn; function fn(){ }//fn被聲明成函數(shù)格式,但未賦值 //fn = 3; console.log(fn);//
-
步驟3
var fn; function fn(){ } fn = 3;//被賦值瞪浸,同時(shí)重新變?yōu)樽兞扛袷?console.log(fn);
綜上
var fn;// 變量聲明前置
function fn(){
}// fn被聲明成函數(shù)格式儒将,但未賦值
fn = 3;//被賦值,同時(shí)重新變?yōu)樽兞扛袷?console.log(fn);//3
6.如下代碼的輸出对蒲?為什么 (難度3)
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
可看作如下
function fn(fn2){
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
fn(10);
7.如下代碼的輸出钩蚊?為什么 (難度3)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn)); //Uncaught TypeError: fn is not a function
可將JS的解析順序視為
var fn;
function fn(fn){
console.log(fn);//error
}
fn = 1;
console.log(fn(fn));//所以error
8.如下代碼的輸出贡翘?為什么 (難度**)
//作用域
console.log(j);//undefined
console.log(i);//undefined
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);//10
console.log(j);//100
可將JS的解析順序視為
var i;
var j;//變量聲明前置
console.log(j);
console.log(i);
for( i=0; i<10; i++){
j = 100;
}//for語句非函數(shù),不存在函數(shù)作用域砰逻,相當(dāng)于直接定義的變量(具體看下面的解析)
console.log(i);
console.log(j);
9.如下代碼的輸出鸣驱?為什么 (難度****)
fn();
var i = 10;
var fn = 20;
console.log(i);
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){
i = 100;
}
}
可將JS的解析順序視為
var i;
var fn;
function fn(){
var i;
function fn2(){
i = 100;
}
console.log(i);// undefined
i = 99;
fn2();//調(diào)用fn2,作用相當(dāng)于:i = 100;
console.log(i);//100
}
fn();//即結(jié)果為:undefined,100
i =10;
fn = 20;
console.log(i);//結(jié)果為:10
10.如下代碼的輸出?為什么 (難度*****)
var say;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1); }( 10 ));//立即執(zhí)行函數(shù)表達(dá)式得到10-2的遞減
say = 0;//say變量被賦值0并輸出
console.log(say);
本教程版權(quán)歸屬于 fin 及 饑人谷 所有蝠咆,轉(zhuǎn)載請(qǐng)說明來源~