函數(shù)聲明和函數(shù)表達式有什么區(qū)別
- 函數(shù)聲明的本質(zhì)是使用
function
聲明一個函數(shù),而函數(shù)表達式的本質(zhì)是將一個函數(shù)賦值給一個變量弄息; - 函數(shù)聲明不必放在函數(shù)調(diào)用之前猬膨,而函數(shù)表達式必須放在調(diào)用函數(shù)之前。
什么是變量的聲明前置答毫?什么是函數(shù)的聲明前置
在一個作用域下褥民,所有的var
聲明變量的語句在被解析時都會被前置镊讼,例如:
console.log(a);
var a = 3;
console.log(a);
上述語句在解析時會自動將var a
這條聲明語句前置誉尖,再執(zhí)行:
console.log(a);
a = 3;
console.log(a);
同理,function
聲明的函數(shù)也會被前置劣领,例如:
sayHello();
function sayHello(){
console.log('hello');
}
也會將聲明語句前置耘拇,再執(zhí)行sayHello();
撵颊。
這也解釋了為什么函數(shù)聲明不必放在函數(shù)調(diào)用之前。
arguments 是什么
在函數(shù)內(nèi)部惫叛,我們可以使用arguments[i]
來獲取函數(shù)中相對應(yīng)的某個參數(shù)倡勇。
這樣做可以簡化函數(shù)語句,避免定義一些不必要的參數(shù)嘉涌,但會令函數(shù)的可讀性變差妻熊。
函數(shù)的"重載"怎樣實現(xiàn)
由于JS屬于弱類型語言,所以它不能像某些強類型語言一樣實現(xiàn)重載仑最,在JS中同名函數(shù)會進行覆蓋扔役。
要實現(xiàn)類似重載的功能,我們可以通過檢查傳入?yún)?shù)的類型和數(shù)量词身,來執(zhí)行相應(yīng)的邏輯語句厅目。
立即執(zhí)行函數(shù)表達式是什么?有什么作用
(function(){
var a = 1;
})()
類似上述語句法严。我們將一個匿名函數(shù)用小括號括起损敷,并在末尾加一對小括號,這樣的函數(shù)在被讀取到時會立即被調(diào)用和執(zhí)行深啤。這樣的寫法相當(dāng)于將聲明函數(shù)和調(diào)用函數(shù)合并拗馒。
它的主要作用在于隔離作用域,避免污染全局變量溯街。
求n!诱桂,用遞歸來實現(xiàn)
function factor(n){
if(n<0){
return'對不起,負(fù)數(shù)沒有階乘呈昔!'
}
if(n===0){
return 1;
}
else{
return n*factor(n-1)
}
}
以下代碼輸出什么挥等?
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('饑人谷', 2, '男'); 輸出:
name:饑人谷
age:2
sex:男
['饑人谷', 2, '男']
name valley
getInfo('小谷', 3); 輸出:
name:小谷
age:3
sex:undefined
['小谷',3]
name valley
getInfo('男'); 輸出:
name:男
age:undefined
sex:undefined
['男']
name valley
寫一個函數(shù),返回參數(shù)的平方和堤尾?
function sumOfSquares(){
var sum = 0;
for(i=0;i<arguments.length;i++){
sum = sum + arguments[i]*arguments[i]
}
return sum;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
如下代碼的輸出肝劲?為什么
console.log(a); //undefined
var a = 1;
console.log(b); //報錯
變量a的聲明會前置,但賦值不會。所以console.log(a);
相當(dāng)于只聲明了變量卻沒有賦值辞槐,所以輸出undefined掷漱;
變量b既沒有聲明也沒有賦值,所以console.log(b);
報錯榄檬。
如下代碼的輸出卜范?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
輸出“hello world”和報錯。
因為function sayName(name)
是一個函數(shù)聲明鹿榜,它可以放在調(diào)用函數(shù)之后海雪,而不影響函數(shù)的執(zhí)行;而var sayAge = function(age)
則是一個函數(shù)表達式犬缨,只有其中的var sayAge
前置了喳魏,所以sayAge
是一個變量而不是函數(shù),因此sayAge(10);
會報錯怀薛。
如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
//最終輸出為:10
/*
1.
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//聲明 foo 時 得到下面
foo.[[scope]] = globalContext.AO
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
2.
barContext = {
AO: {
x: 30
},
Scope: bar.[[scope]] //globalContext.AO
}
3.
fooContext = {
AO: {},
Scope: foo.[[scope]] // globalContext.AO
}
*/
如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
//最終輸出為:30
/*
1.
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
2.
barContext = {
AO: {
x: 30,
foo: function
},
Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的執(zhí)行上下文里聲明 foo 時 得到下面
foo.[[scope]] = barContext.AO
3.
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
*/
以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
//最終輸出為:30
/*
1.
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
2.
barContext = {
AO: {
x: 30,
function
},
Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的執(zhí)行上下文里聲明 function 時 得到下面
function.[[scope]] = barContext.AO
3.
functionContext = {
AO: {},
Scope: function.[[scope]] // barContext.AO
}
*/
以下代碼輸出什么刺彩? 寫出作用域鏈查找過程偽代碼
var a = 1;
function fn(){
console.log(a)
var a = 5
console.log(a)
a++
var a
fn3()
fn2()
console.log(a)
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn()
console.log(a)
/*
1.
globalContext = {
AO: {
a: 1
fn: function
fn3: function
},
Scope: null
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO
2.
fnContext = {
AO: {
a: undefined,
fn2: function,
};
Scope: fn.[[scope]] //globalContext.AO
}
fn2.[[scope]] = fnContext.AO
3.
fn3Context = {
AO:{
a: 200,
},
Scope:fn3.[[scope]]//globalContext.AO
}
4.
fn2ConText = {
AO:{
a: 20,
},
Scope:fn2.[[scope]]//fnContext.AO
}
開始執(zhí)行代碼
-var a = 1; //聲明全局變量a = 1,即globalContext中a = 1枝恋;
-function fn() //調(diào)用函數(shù)fn()创倔;
-console.log(a) //var a聲明前置但未賦值,所以輸出undefined焚碌;
-var a = 5; //賦值a = 5畦攘,即fnContext中a = 5;
-console.log(a) //輸出5十电;
-a++ //a值自增變?yōu)?知押,即fnContext中a變?yōu)?;
-fn3 //調(diào)用函數(shù)fn3()鹃骂;
-console.log(a) //在globalContext中a = 1台盯,所以輸出1;
-a = 200 //globalContext中a值變?yōu)?00畏线;
-fn2() //調(diào)用函數(shù)fn2()静盅;
-console.log(a) //在fnContext中a = 6,所以輸出6寝殴;
-a=20 //fnContext中a值變?yōu)?0蒿叠;
-console.log(a) //在fnContext中a = 20,所以輸出20蚣常;
-console.log(a) ///globalContext中a = 200市咽,所以輸出200。
因此抵蚊,最終輸出結(jié)果為:undefined 5 1 6 20 200
*/