1.函數(shù)聲明和函數(shù)表達式有什么區(qū)別?
1.函數(shù)聲明:function functionName (){}
函數(shù)聲明(Function Declaration) 可以定義命名的函數(shù)變量,而無需給變量賦值。Function Declaration 是一種獨立的結(jié)構(gòu),不能嵌套在非功能模塊中??梢詫⑺惐葹?Variable Declaration(變量聲明)。就像 Variable Declaration 必須以“var”開頭一樣,F(xiàn)unction Declaration 必須以“function”開頭。
2.函數(shù)表達式: var fn = function (){}
函數(shù)表達式(Function Expression)將函數(shù)定義為表達式語句(通常是變量賦值)的一部分。通過 函數(shù)表達式定義的函數(shù)可以是命名的,也可以是匿名的。函數(shù)表達式不能以“function”開頭
區(qū)別:用函數(shù)聲明定義的函數(shù),函數(shù)可以在函數(shù)聲明之前調(diào)用,聲明不必放在調(diào)用的前面。而用函數(shù)表達式定義的函數(shù)只能在聲明之后調(diào)用?!靖驹蛟谟诮馕銎鲗@兩種定義方式讀取的順序不同:解析器會事先讀取函數(shù)聲明,即函數(shù)聲明放在任意位置都可以被調(diào)用;對于函數(shù)表達式,解析器只有在讀到函數(shù)表達式所在那行的時候才解析聲明并執(zhí)行】
2.什么是變量的聲明前置?什么是函數(shù)的聲明前置?
- 變量聲明前置:只是提升聲明部分(未賦值狀態(tài)),賦值部分保持原位置不變。
實例:
function say(){
console.log(name);
var name='tom';
console.log(name);
}
say();
上面式子可視為
function say(){
var name;//變量name聲明前置,由于name未賦值,故為undefined
console.log(name);//存在局部name,則無視全局name
name='tom';//變量賦值保持原位,變量name被賦值為'tom'
console.log(name);//輸出'tom'
}
say();//輸出結(jié)果為 undefined tom
- 函數(shù)聲明前置:會將函數(shù)的聲明和定義全都提升至作用域頂部。
實例:
var say = function(){
console.log('1');
};
function say(){
console.log('2');
};
say();
上面式子可視為
var say; //變量聲明前置
function say(){
console.log('2');
} //函數(shù)聲明前置
say = function(){ //變量賦值保持原位執(zhí)行,say函數(shù)被覆蓋
console.log('1');
};
say(); //輸出'1'
注意:函數(shù)的聲明優(yōu)先級高于變量的聲明。
3.arguments是什么?
arguments 是一個類數(shù)組對象。代表傳給一個function的參數(shù)列表。
- arguments length屬性
arguments 是個類數(shù)組對象,其包含一個 length 屬性,可以用 arguments.length 來獲得傳入函數(shù)的參數(shù)個數(shù)。
示例:
function func() {
console.log( arguments.length);
}
func();// 0
func(1, 2);// 2
func(1, 2, 3);// 3
- arguments 轉(zhuǎn)數(shù)組
通常使用下面的方法來將 arguments 轉(zhuǎn)換成數(shù)組:
Array.prototype.slice.call(arguments);
還有一個更簡短的寫法:
[].slice.call(arguments);
4.函數(shù)的"重載"怎樣實現(xiàn)?
首先申明,在 JS 中沒有重載! 同名函數(shù)會覆蓋。 但可以在函數(shù)體針對不同的參數(shù)調(diào)用執(zhí)行相應(yīng)的邏輯。
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);//輸出結(jié)果byron 26
printPeopleInfo('Byron', 26, 'male');//輸出結(jié)果byron 26 male
5.立即執(zhí)行函數(shù)表達式是什么?有什么作用?
- 立即執(zhí)行函數(shù)表達式
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
(function(){ /* code */ }());
- 立即執(zhí)行函數(shù)表達式的作用:
1.不必為函數(shù)命名,避免了污染全局變量;
2.立即執(zhí)行函數(shù)表達式內(nèi)部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量,隔離作用域。
6.求n!,用遞歸來實現(xiàn)
function factor(n){
if (n < 0 ) {
return "wrong";
}
else if (n === 1 || n === 0) {
return 1;
}
else {
return n * factor(n-1);
};
factor(5) //120
7.以下代碼輸出什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';//將vally賦給第一個參數(shù)name
console.log('name', name);
}
getInfo('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
輸出結(jié)果
name: 饑人谷
age: 2
sex: 男
["饑人谷", 2, "男"]
name valley
name: 小谷
age: 3
sex: undefined
["小谷",3]
name valley
name: 男
age: undefined
sex: undefined
["男"]
name valley
8.寫一個函數(shù),返回參數(shù)的平方和
function sumOfSquares(){
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
如下:
function sumOfSquares(){
var i =arguments.length
var sum=0
for(var n=0;n<i;n++){
sum=sum+arguments[n]*arguments[n]
}
return sum
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result)
console.log(result2)
9.如下代碼的輸出?為什么
console.log(a);
var a = 1;
console.log(b);
聲明前置:
var a ;//變量聲明前置
console.log(a);//輸出undefined
a=1;
console.log(b);//b沒有聲明,報錯 Uncaught ReferenceError: b is not defined
10.如下代碼的輸出?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
function sayName(name){
console.log('hello ', name);
}//函數(shù)聲明前置
sayName('world');//輸出結(jié)果為hello world
sayAge(10);//報錯 sayAge is not a function
var sayAge = function(age){
console.log(age);
};//函數(shù)表達式須放在調(diào)用前面,因為函數(shù)表達式只有執(zhí)行到這一行才會去聲明
11.如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
/* 1.
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
},
Scope:bar.[[scope]] = globalContext.AO
}
x變成30
3.調(diào)用foo()
fooContext = {
AO:{},
Scope:foo.[[scope]] = globalContext.AO
}
輸出10
*/
12.如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
/*
1.
globalContext={
AO:{
x:10
bar:function
}
scope: null
}
bar.[[scope]]=globalContext.AO
2.調(diào)用函數(shù)bar()
barContext={
AO:{
x:30
foo:function
}
scope: bar.[[scope]]=globalContext.AO
}
foo.[[scope]]=barContext.AO
3.調(diào)用函數(shù)foo()
fooContext={
AO:{}
}
scope: foo.[[scope]]=barContext.AO
輸出30
*/
13.如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
/*
1.
globalContext={
AO:{
X:10
bar:function
}
scope: null
}
bar.[[scope]]=globalContext.AO
2.調(diào)用bar()
barContext={
AO:{
X:30
function
}
scope: bar.[[scope]]=globalContext.AO
}
function.[[scope]]=barContext.AO
3.調(diào)用立即執(zhí)行函數(shù)
fonctionContext={
AO:{}
scope:function.[[scope]]=barContext.AO
}
輸出30
*/
14.1以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
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/200
fn:function
fn3:function
}
scope:none
fn.[[scope]]=globalContext.AO
fn3.[[scope]]=globalContext.AO
}
2.調(diào)用函數(shù)fn()
fnContext={
AO:{
a:undefined/5/6/20
fn2:function
}
scope: fn.[[scope]]=globalContext.AO
}
fn2.[[scope]]=fnContext.AO
3.調(diào)用函數(shù)fn3()
fn3Context={
AO:{}
scope:fn3.[[scope]]=globalContext.AO
}
4.調(diào)用函數(shù)fn2()
fn2Context={
AO:{}
scope:fn2.[[scope]]=fnContext.AO
}
開始執(zhí)行:
console.log(a)//fn()變量初始值為undefined,所以輸出undefined
var a=5//fncontext.AO中的a賦值為5
console.log(a)//輸出5
a++//fnContext.AO中的a賦值為加1為6
var a//聲明a賦值不變
fn3()//調(diào)用fn3()
執(zhí)行fn3():
console.log(a)//fn3.[[scope]]=globalContext.AO,因為fn3Context.AO中沒有a值,所以
去globalContext.AO找,a值為1,所以輸出1
a = 200// globalContext.AO中a賦值為200
執(zhí)行完fn3,跳出fn3,繼續(xù)執(zhí)行fn中的fn2()
fn2()//調(diào)用執(zhí)行fn2
console.log(a)//此時fnContext.AO中的a賦值為6,所以輸出6
a=20// fnContext.AO中的a賦值為20
跳出fn2,繼續(xù)執(zhí)行fn
console.log(a)//此時fnContext.AO中的a賦值為20,輸出20
此時fn執(zhí)行結(jié)束,繼續(xù)執(zhí)行
console.log(a)//此時globalContext.AO中a賦值為200
綜上輸出結(jié)果:undefined 5 1 6 20 200
*/