1 函數(shù)聲明和函數(shù)表達式有什么區(qū)別?
函數(shù)聲明:定義一個具有指定參數(shù)的函數(shù),函數(shù)聲明最重要的特征就是函數(shù)聲明提升,意思是在執(zhí)行代碼之前就會讀取函數(shù)聲明.
sayHi();
function sayHi(){
alert("hi world");
}
//不會報錯,因為函數(shù)聲明在sayHi()在函數(shù)sayHi()之前已經(jīng)讀取
name :函數(shù)名
param:要傳遞給函數(shù)的參數(shù)的名稱。不同引擎中的最大參數(shù)數(shù)量不同。一個函數(shù)最多有255個參數(shù)
statements:包含函數(shù)體的語句。
描述:
一個被函數(shù)聲明創(chuàng)建的函數(shù)是一個 Function 對象,具有 Function 對象的所有屬性鞋诗、方法和行為。
參考
-
函數(shù)表達式
用函數(shù)表達式定義的函數(shù)在使用之前必須先賦值
sayHi();
var sayHi = function() {
alert("hi wrold");
}
//報錯迈嘹,函數(shù)sayHi()調(diào)用之前并未賦值
-
區(qū)別
1 函數(shù)表達式定義的函數(shù)在使用之前必須先賦值,而函數(shù)聲明不必.
2 函數(shù)表達式與函數(shù)聲明的最主要區(qū)別是函數(shù)名稱(function name)削彬,在函數(shù)表達式中可忽略它,從而創(chuàng)建匿名函數(shù).
2 什么是變量的聲明前置秀仲?什么是函數(shù)的聲明前置?
變量聲明前置就是在一個作用域塊中融痛,所有的變量都被放在塊的開始出聲明
1 var a = 1;
2 function main() {
3 console.log(a);//1
4 }
5 main();//輸出1
1 var a = 1;
2 function main() {
3 console.log(a);
4 var a = 2;
5 }
6 main()//輸出undefined
為什么輸出undefined,因為腳本在執(zhí)行的時候會自動將變量聲明前置
函數(shù)的聲明前置:在一個作用域下,同var 聲明的變量一樣神僵,function 聲明的函數(shù)也會前置雁刷。函數(shù)的聲明前置優(yōu)先級高于變量的聲明前置。
var a = 3;
console.log(a); //3
sayHello();
function sayHello(){
console.log('hello');//hello
}
執(zhí)行時語句順序如下:
var a
function sayHello(){}
console.log(a);//undefined
a=3
console.log(a); //3
sayHello();
3 arguments 是什么?
- arguments對象是所有函數(shù)中可用的局部變量,你可以使用arguments對象在函數(shù)中引用函數(shù)的參數(shù)保礼。此對象包含傳遞給函數(shù)的每個參數(shù)的條目沛励,第一個條目的索引從0開始。例如炮障,如果一個函數(shù)傳遞了三個參數(shù)目派,你可以參考它們?nèi)缦拢?/li>
arguments[0]
arguments[1]
arguments[2]
參數(shù)也可以被設置:
arguments[1] = 'new value';
arguments對象不是一個 Array它類似于數(shù)組
4 函數(shù)的"重載"怎樣實現(xiàn)?
- Javascript中,先定義的函數(shù)铝阐,可以被后定義的函數(shù)覆蓋址貌。因此Javascript不支持函數(shù)的重載。比如下面的例子:
<script type="text/javascript">
function p(a, b, c) {
alert(a+b+c);
}
function p(a, b) {
alert(a+b);
}
p(1,2,3);//alert 3;
</script>
雖然有函數(shù)p(a, b, c)徘键,但是由于語言的特性,該函數(shù)被后面的p(a,b)所覆蓋
- 但是利用js的arguments遍蟋,可以實現(xiàn)JavaScript的重載吹害。
function showMessage(){
if(arguments.length==1){
console.log(arguments[0]);
}else if( arguments.length==2){
console.log(arguments[0]+"說:"+arguments[1]);
}else{
return false;
}
}
showMessage("Hi!");
showMessage("張三","Hi 你好");
5 立即執(zhí)行函數(shù)表達式是什么?有什么作用
我們需要在定義函數(shù)之后虚青,立即調(diào)用該函數(shù).這時不能在函數(shù)的定義之后加上圓括號它呀,這會產(chǎn)生語法錯誤.
function(){ /* code */ }();
// SyntaxError: Unexpected token
產(chǎn)生這個錯誤的原因是,function這個關(guān)鍵字即可以當作語句,也可以當作表達式纵穿。
// 語句
function f() {}
// 表達式
var f = function f() {}
為了避免解析上的歧義下隧,JavaScript引擎規(guī)定,如果function關(guān)鍵字出現(xiàn)在行首谓媒,一律解釋成語句淆院。因此,JavaScript引擎看到行首是function關(guān)鍵字之后句惯,認為這一段都是函數(shù)的定義土辩,不應該以圓括號結(jié)尾,所以就報錯了抢野。
解決方法就是不要讓function出現(xiàn)在行首拷淘,讓引擎將其理解成一個表達式。最簡單的處理指孤,就是將其放在一個圓括號里面启涯。
- 通常情況下,只對匿名函數(shù)使用這種“立即執(zhí)行的函數(shù)表達式”恃轩。
它的目的有兩個:一是不必為函數(shù)命名逝嚎,避免了污染全局變量;二是IIFE內(nèi)部形成了一個單獨的作用域详恼,可以封裝一些外部無法讀取的私有變量补君。
// 寫法一
var tmp = newData;
processData(tmp);
storeData(tmp);
// 寫法二
(function (){
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
上面代碼中,寫法二比寫法一更好昧互,因為完全避免了污染全局變量挽铁。
6 求n!,用遞歸來實現(xiàn)
function jiechen(n) {
if(n === 1){
return 1;
}
return n * jiechen(n-1);
}
jiechen(4);//24
7 以下代碼輸出什么敞掘?
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, '男');
getInfo('小谷', 3);
getInfo('男');
輸出:
name: 饑人谷
age: 2
sex: 男
["饑人谷", 2, "男"]
name valley
name: 小谷
age: 3
sex: undefined
["小谷", 3]
name valley
name: 男
age: undefined
sex: undefined
["男"]
name valley
undefined
8 寫一個函數(shù)叽掘,返回參數(shù)的平方和?
function sumOfSquares() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
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
9 如下代碼的輸出玖雁?為什么
console.log(a);
var a = 1;
console.log(b);
輸出:
undefined //原因:變量聲明前置var a;
"error" //沒有聲明變量b
10 如下代碼的輸出更扁?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
輸出:
"hello world"
"error" //報錯原因:函數(shù)表達式定義的函數(shù)在使用之前必須先賦值.
改為如下:
var sayAge = function(age){
console.log(age);
};
sayAge(10);
11 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar() ;
function foo() {
console.log(x);
}
function bar(){
var x = 30;
foo();
}
輸出:10
原因:
全局作用域: {
可使用變量: x : 10
可使用的函數(shù): foo() , bar()
}
foo()作用域: {
可使用變量: x : 10
}
bar()作用域: {
可使用變量: x : 30
可使用的函數(shù): foo()
}
運行邏輯:
先申明全局變量 x = 10;
執(zhí)行bar()函數(shù);
申明一個僅在bar()作用域內(nèi)訪問的局部變量x=30;
執(zhí)行foo()函數(shù),執(zhí)行console.log(x)方法;
但沒在當前作用域下找到?x變量,但全局作用域的x=10可以使用,完成輸出;
12 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar();
function bar(){
var x = 30;
function foo(){
console.log(x);//此處輸出30
}
foo();
}
輸出:30
原因:
全局作用域: {
可使用變量: x : 10
可使用的函數(shù): bar()
}
foo()作用域: {
可使用變量: x : 10
}
bar()作用域: {
可使用變量: x : 30
可使用的函數(shù): foo()
}
運行邏輯:
運行bar()-->運行 foo(), 找到可使用的局部變量x=30,輸出x=30;
13 以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼
var x = 10;
bar();
function bar(){
var x = 30;
(function (){
console.log(x);
})();
}
輸出:30
原因:
因為是立即調(diào)用函數(shù)所以上面代碼等價于下面的:
var x = 10;
bar();
function bar(){
var x = 30;
function fn(){
console.log(x);
};
fn();
}
全局作用域{
可用變量:x=10 ;
函數(shù):bar()
}
bar()作用域{
可用變量 x=30
函數(shù):fn()
}
14 以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var a = 1;
function fn(){
console.log(a);//第一次輸出:undefined:因為下面 var a = 5;所以提前申明了var a ;找不到a報錯.
var a = 5;
console.log(a);//第二次輸出5:因為在當前作用域下找到了a=5;
a++;//a=6
var a;
fn3();
fn2();
console.log(a);//第五次輸出:20,因為a的值已經(jīng)在調(diào)用fn2()時被修改.
function fn2(){
console.log(a);//第四次輸出:6,因為這作用域里沒有var a 申明 ,去上一級即fn()里作用域找,此時a++后,a=6.所以輸出6.
a = 20;// 給fn()里的變量a賦值為20.并保存在內(nèi)存里
}
}
function fn3(){
console.log(a);// 第三次輸出:1,因為fn3()屬于全局函數(shù),這里沒var a,就去全局找到var a =1
a = 200; //找到了全局a ,在這一步給全局變量a 賦值為200.并保存在內(nèi)存里.
}
fn();
console.log(a);//第六次輸出:200,因為去全局找,而a的值已經(jīng)在調(diào)用fn3()時被修改.
輸出:
undefined
5
1
6
20
200
原因:
全局作用域{
可用變量: a = 1
可用函數(shù): fn() ; fn3(); ;
}
fn()作用域內(nèi){
可用變量: a =5;
可用函數(shù):fn2()
}
fn2()作用域內(nèi){
可用變量: a =20
}
fn3()作用域內(nèi){
可用變量: a=200
}
運行邏輯:
代碼//后內(nèi)容:為解釋