如題,本文介紹函數(shù)與作用域的相關(guān)知識(shí)
1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
-
函數(shù)聲明:使用function關(guān)鍵字可以聲明一個(gè)函數(shù)
例:
function foo(){}
-
函數(shù)表達(dá)式:意即將一個(gè)匿名函數(shù)賦值給一個(gè)變量
例:
var foo=function(){}
-
區(qū)別:
(1)函數(shù)聲明必須有標(biāo)識(shí)符悬襟,也就是常說(shuō)的函數(shù)名端仰;函數(shù)表達(dá)式可以省略函數(shù)名
(2)函數(shù)的聲明不必放到調(diào)用的前面窿侈,函數(shù)調(diào)用的時(shí)候才會(huì)被執(zhí)行。函數(shù)的表達(dá)式則必須放到調(diào)用的前面。
(3)函數(shù)聲明在JS解析時(shí)進(jìn)行函數(shù)提升,因此在同一個(gè)作用域內(nèi)迎瞧,不管函數(shù)聲明在哪里定義,該函數(shù)都可以進(jìn)行調(diào)用逸吵。而函數(shù)表達(dá)式的值是在JS運(yùn)行時(shí)確定凶硅,并且在表達(dá)式賦值完成后,該函數(shù)才能調(diào)用扫皱。
在程序執(zhí)行前咏尝,會(huì)先獲取函數(shù)聲明聲明的函數(shù),獲取變量的聲明啸罢,這里變量的聲明只是先開(kāi)辟一個(gè)空間,然后給了個(gè)名字胎食,之后到該變量名賦值的時(shí)候扰才,才有值,也就是說(shuō)厕怜,在未得到該變量的賦值前衩匣,使用該變量會(huì)得到undefined蕾总。
2.什么是變量的聲明前置?什么是函數(shù)的聲明前置
javascript的變量聲明具有hoisting機(jī)制琅捏,JavaScript引擎在執(zhí)行的時(shí)候生百,會(huì)把所有的聲明都提升到當(dāng)前作用域的最前面
-
變量聲明前置就是在一個(gè)作用域塊中,所有的變量都被放在塊的開(kāi)始處聲明
變量的聲明前置柄延,在程序運(yùn)行前蚀浆,先獲取變量的名字,到該變量的賦值語(yǔ)句搜吧,才為該變量賦值市俊,再此前都是undefined
函數(shù)的聲明前置:function 函數(shù)名(){}聲明了一個(gè)函數(shù),在程序運(yùn)行前滤奈,提取所有函數(shù)聲明的函數(shù)摆昧,之后才正式開(kāi)始運(yùn)行函數(shù),所以蜒程,無(wú)論函數(shù)聲明的函數(shù)執(zhí)行語(yǔ)句放在程序的最前面绅你,或者程序的最后面,都能夠正常執(zhí)行
3.arguments 是什么
arguments是函數(shù)內(nèi)部的一個(gè)對(duì)象昭躺,對(duì)應(yīng)著傳進(jìn)來(lái)的參數(shù)忌锯,是一個(gè)類(lèi)數(shù)組對(duì)象,沒(méi)有數(shù)組的操作方法窍仰。
- 特點(diǎn):
(1)對(duì)象有l(wèi)ength屬性且length的值就是對(duì)象里屬性的數(shù)量
(2)每個(gè)傳進(jìn)來(lái)的參數(shù)對(duì)應(yīng)著arguments[0],arguments[1]汉规,有先后順序之分,通過(guò)下標(biāo)獲取到對(duì)應(yīng)值
比如
function fn(name,age){
console.log(arguments[0];);
console.log(arguments[1];);
}
4.函數(shù)的"重載"怎樣實(shí)現(xiàn)
定義:重載函數(shù)就是在同一作用域內(nèi)驹吮,可以有一組具有相同函數(shù)名针史,不同參數(shù)列表的函數(shù),執(zhí)行相應(yīng)的功能
在JS中沒(méi)有函數(shù)重載碟狞。相同的函數(shù)名字啄枕,如果定義的參數(shù)個(gè)數(shù)不一樣,后出現(xiàn)的會(huì)覆蓋先出現(xiàn)的 同名函數(shù)后面的會(huì)覆蓋前面的族沃。
-
但我們可以通過(guò)在函數(shù)體內(nèi)針對(duì)不同的參數(shù)調(diào)用執(zhí)行相應(yīng)的邏輯频祝,也就類(lèi)似實(shí)現(xiàn)了“重載”的效果。
例子 function printPeopleInfo(name, age, sex){ if(name){ console.log(name); } if(age){ console.log(age); } if(sex){ console.log(sex); } } printPeopleInfo('Byron', 26); printPeopleInfo('Byron', 26, 'male');
5.立即執(zhí)行函數(shù)表達(dá)式是什么脆淹?有什么作用
- 寫(xiě)法
(1)(function(){ /* code */ }());
// Crockford 推薦這個(gè)
(2)(function(){ /* code */ })();
// 這個(gè)同樣運(yùn)行正常
- 作用
(1) 函數(shù)會(huì)立即執(zhí)行常空。
(2) 隔離作用域(這個(gè)匿名函數(shù)中的變量與外部環(huán)境的變量隔離,防止了變量的命名沖突盖溺,形成了一個(gè)獨(dú)立的空間漓糙,有助于代碼模塊化。)
6.求n!烘嘱,用遞歸來(lái)實(shí)現(xiàn)
- 遞歸4個(gè)特點(diǎn):
(1)自己調(diào)用自己
(2)設(shè)定終止條件
(3)優(yōu)點(diǎn):算法簡(jiǎn)單
(4)缺點(diǎn):效率低
-
例子
function factor(n){ if(n===1){ console.log(n); return n; } var nn=n*factor(n-1) console.log(nn) return nn } factor(5)````
//1*2*3*4*5 結(jié)果:1 2 6 24 120
7.以下代碼輸出什么昆禽?(PS: //注釋就是結(jié)果)
function getInfo(name, age, sex){
console.log('name:',name); //饑人谷-->小谷-->男
console.log('age:', age); //2-->3-->undefined
console.log('sex:', sex); //男-->undefined-->undefined
console.log(arguments); //空(沒(méi)有指定下標(biāo))
arguments[0] = 'valley';
console.log('name', name); //name valley
}
getInfo('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
8. 寫(xiě)一個(gè)函數(shù)蝗蛙,返回參數(shù)的平方和?
<script>
function sumOfSquares(){
var result = 0;
if(arguments.length>0){
for(var i=0;i<arguments.length;i++){
result += arguments[i]*arguments[i];
}
}
return result
}
var result =sumOfSquares(2,3,4)
var result2 =sumOfSquares(1,3)
console.log(result)
console.log(result2)
</script>
9.如下代碼的輸出醉鳖?為什么
console.log(a);
var a = 1; //undefined
console.log(b); //報(bào)錯(cuò)
- 結(jié)果:undefined和報(bào)錯(cuò)
- 原因:
(1)變量a的定義var a = 1;
應(yīng)該放到console.log(a);
的前面捡硅,變量應(yīng)該先定義后輸出。
(2)b是沒(méi)有被聲明的盗棵,肯定不能直接輸出壮韭。
10.如下代碼的輸出?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
}
輸出 :hello,world以及報(bào)錯(cuò)
原因:
function sayName(name){}
是一個(gè)函數(shù)漾根,它可以直接調(diào)用賦值泰涂,聲明和調(diào)用不分先后,沒(méi)有順序
var sayAge = function(age){}
是一個(gè)函數(shù)表達(dá)式辐怕,想要賦值必須先要聲明逼蒙,應(yīng)該放到function(age){}
后面
11.如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
/*
1.第一步:執(zhí)行上下文
globalContext{
AO:{
x=10;
foo:function();
bar:function();
},
Scope:null
}
foo.[[scope]]=globalContext.AO
bar.[[scope]]=globalContext.AO
2.第二步:調(diào)用bar()
barContext={
AO:{
x:30
foo:function
},
Scope:bar.[[scope]]//globalContext.AO
}
bar() //結(jié)果 x:30
3.第三步:調(diào)用foo()
fooContext={
AO:{}
Scope:foo.[[scope]]=globalContext.AO
}
foo() //結(jié)果 x:10
//最終結(jié)果: x:10
*/
12. 如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
/*
第一步:執(zhí)行上下文
globalContext{
AO:{
x:10
bar:function
}
Scope:null
}
bar.[[scope]]=globalContext.AO
第二步:調(diào)用bar()
barContext={
AO:{
x:30
foo:function
}
Scope:bar.[[scope]]=globalContext.AO
}
bar() //結(jié)果 x:30
第三步:調(diào)用foo()
fooContext={
A0:{ }
Scope:foo.[[scope]]=barContext.AO
}
foo() //結(jié)果 x:30
// bar(){
// foo()
// }
// 最終結(jié)果 x:30
*/
13. 以下代碼輸出什么? 寫(xiě)出作用域鏈的查找過(guò)程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
/*
第一步:執(zhí)行上下文
globalContext{
AO:{
x:10;
bar:function
}
Scope:null
}
bar.[[scope]]=globalContext.AO
第二步:調(diào)用bar()
barContext={
AO:{
x=30
:function
}
Scope:bar.[[scope]]=globalContext.AO
}
第三步:立即執(zhí)行function ()
functionContext={
AO:{ }
Scope:function.[[scope]]//barContext.AO
}
// 最終結(jié)果 x:30
*/
14. 以下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
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)
/*
//第一步:執(zhí)行上下文
globalContext:{
AO:{
a:1
fn:function
fn3:function
}
Scope:null
}
fn.[[scope]]=globalContext.A0
fn3.[[scope]]=globalContext.AO
//調(diào)用 fn()
fnContext:{
AO:{
a:6
fn3:function
fn2:function
}
Scope:null
}
fn3[[scope]]=fnContext.AO
fn2[[scope]]=fnContext.AO
//調(diào)用 fn2()
fn2Context:{
AO:{
}
Scope:fn2.[[scope]]=fnContext.AO
}
//調(diào)用 fn3()
fn3Context:{
AO:{
}
Scope:fn3.[[scope]]=globalContext.AO
}
// 最終結(jié)果 a:undefined 5 1 6 20 200
*/
本文部分內(nèi)容來(lái)自于饑人谷寄疏,版權(quán)歸饑人谷_海瀚和饑人谷所有是牢,轉(zhuǎn)載需說(shuō)明來(lái)源