函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*)
在javascript中,函數(shù)有兩種定義寫法,函數(shù)定義表達(dá)式和函數(shù)聲明,其例子分別如下所示:
var test = function(x){
return x;
}
function test(x){
return x;
}
盡管函數(shù)定義表達(dá)式和函數(shù)聲明語句包含相同的函數(shù)名,并且都創(chuàng)建了新的函數(shù)對象,但是這二者卻有區(qū)別。
-函數(shù)聲明語句中的函數(shù)名是一個變量名,變量指向函數(shù)對象。
-函數(shù)定義表達(dá)式和通過var聲明變量一樣,其函數(shù)被提前到了腳本或函數(shù)的頂部,因此它在整個腳本和或函數(shù)內(nèi)都是可見的。這樣的話,只有函數(shù)變量聲明提前了,函數(shù)的初始化代碼仍然在原來的位置。但是使用函數(shù)聲明的話,函數(shù)名稱和函數(shù)體均提前了,即腳本中的函數(shù)和函數(shù)中嵌套的函數(shù)都會在當(dāng)前上下文中其它代碼之前聲明,也即可以在聲明一個函數(shù)之前調(diào)用它。
例如:
test(1);
function test(x){
console.log(x);
}
上面代碼能正常執(zhí)行。輸出結(jié)果為1,這時候函數(shù)變量聲明提前了。相當(dāng)于
function test(x){
console.log(x);
}
test(1);
運(yùn)行不會報錯。
而對于
test(1);
var test = function(x){
console.log(x);
}
而這時,只相當(dāng)于函數(shù)變量聲明提前了,函數(shù)的初始代碼仍然在原位。即:
var test;
test(1);
test = function(x){
console.log(x);
}
當(dāng)運(yùn)行到test(1);的時候就會報錯.
什么是變量的聲明前置?什么是函數(shù)的聲明前置 (**)
-變量的聲明前置:
-所謂的變量聲明前置就是在一個作用域塊中,所有的變量都被放在塊的開始出聲明
例如:
var a=10;
function v(){
console.log(c);
var c=100;
}
v();
這時候運(yùn)行v() 控制臺輸出 undefined;就是因為變量的聲明前置;上面代碼和下面代碼一致。
var a=10;
function v(){
var c;
console.log(c);
c=100;
}
v();
當(dāng)運(yùn)行到console.log(c)的時候變量c只是聲明了。還未定義。則會顯示undefied;
-函數(shù)的聲明前置
-函數(shù)的聲明前置和變量聲明前置類型。只是函數(shù)表達(dá)式并不會發(fā)生聲明前置。例如
console.log(typeof foo);
console.log(typeof bar);
console.log(typeof add);
//函數(shù)的聲明
function foo(){
alert('foo');
}
//命名函數(shù)表達(dá)式
var bar = function(){
alert('bar');
};
// 函數(shù)表達(dá)式-匿名函數(shù)
var add = function(a,b){
return a+b;
};
arguments 是什么
-arguments 是JavaScript里的一個內(nèi)置對象,有的函數(shù)都有屬于自己的一個arguments對象
-函數(shù)的 arguments 對象并不是一個數(shù)組,但是訪問單個參數(shù)的方式與訪問數(shù)組元素的方式相同。
例如:
function main(){
for(var i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
}
main("21a",21,"one")
這樣就利用arguments對傳輸進(jìn)來的數(shù)據(jù)進(jìn)行遍歷。
函數(shù)的重載
-JS中不存在函數(shù)的重載,而C++,java中函數(shù)的重載時利用相同名稱的函數(shù),參數(shù)個數(shù)和參數(shù)順序的不同認(rèn)為是不同的函數(shù),稱之為函數(shù)的重載。
-在JS中,函數(shù)依據(jù)函數(shù)名稱確定唯一性,相同名稱函數(shù),后者會覆蓋前者(即使參數(shù)個數(shù)和參數(shù)順序不同.)
立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用
立即執(zhí)行函數(shù)表達(dá)式是 例如
(function sayHello() {
alert("hello");
}() );
或者:
(function sayHello() {
alert("hello");
}) ();
其主要作用是:
-隔離作用域,當(dāng)函數(shù)執(zhí)行完,其內(nèi)部定義的變量就釋放了,不會與外部變量發(fā)生沖突;相當(dāng)于人為創(chuàng)建一個塊級作用域,而JS本身沒有塊級作用域。
-封裝一段代碼而不會引起而不會遺留任何全局變量,定義的變量都是立即執(zhí)行函數(shù)的局部變量;
什么是函數(shù)的作用域鏈?
當(dāng)代碼在執(zhí)行時候,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。js沒有塊級作用域,只有函數(shù)作用域。
例如:
var color="blue";
function getColor(){
var otherColor="red";
function changeColor(){
vae tempColor=otherColor;
otherColor=color;
color=tempColor;
//這里可以訪問 tempColor otherColor 和color
}
changeColor();
// 這里可以訪問 otherColor,color
}
//這里只能訪問color
getColor();
代碼
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('hunger', 28, '男');
getInfo('hunger', 28);
getInfo('男');
輸入getInfo('hunger', 28, '男'); 的時候輸出{
name:hunger;
age:28;
sex:男;
["hunger", 28, '男'];
name:valley;
}
輸入getInfo('hunger', 28); 的時候輸出{
name:hunger;
age:28;
sex:undefined;
["hunger", 28];
name:valley;
}
輸入getInfo('男');的時候輸出{
name:男;
age:undefined;
sex:undefined;
["男"];
name:valley;
}
2.寫一個函數(shù),返回參數(shù)的平方和?如 (難度**)
function sumOfSquares(){
var sum=null;
for(var i=0;i<arguments.length;i++){
sum+=(arguments[i]*arguments[i]);
}
console.log (sum);
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3..如下代碼的輸出?為什么 (難度*)
console.log(a);
var a = 1;
console.log(b);
_________________________
console.log(a) //輸出 1
console.log(b)//報錯顯示b undefied.
因為發(fā)生了函數(shù)聲明前置,例子代碼與下面代碼相同:
var a;
console.log(a);
a=1;
console.log(b);
4.如下代碼的輸出?為什么?
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
___________
會輸出 hello,world;
sayAge 報錯,顯示undefined
因為變量聲明和函數(shù)聲明會前置,但函數(shù)表達(dá)式不會前置:轉(zhuǎn)換后如下例所示:
var sayage;
function sayName(name){
console.log('hello ', name);
}
sayName('world');
sayAge(10);
ayAge = function(age){
console.log(age);
};
5.如下代碼的輸出?為什么 (難度**)
function fn(){}
var fn = 3;
console.log(fn);
————————
輸出3
var fn;
function fn(){};
fn=3;
console.log(fn);
相當(dāng)于先聲明一個變量fn,再創(chuàng)建一個函數(shù)fn,此時會覆蓋之前聲明的fn,然后 將3賦值給函數(shù)fn,最后輸出3
6..如下代碼的輸出?為什么 (難度***)
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
___________
會輸出
function fn2(){
console.log('fnnn2');
}
------
3
----
function fn(fn2){
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
可以將上例函數(shù)轉(zhuǎn)換為:
function fn(fn2){
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
當(dāng)輸入 fn(10)的時候。
遇到var fn2; 這時候 fn2等于10;
function fn2(){} 沒有被調(diào)用 跳過。
console.log(fn2);輸出函數(shù)fn2:
function fn2(){
console.log('fnn2')
}
然后將3賦值給fn2,
遇到console.log(fn2);輸出3
然后遇到console.log(fn)輸出 函數(shù) fn();
7.如下代碼的輸出?為什么 (難度***)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
報錯fn undefied
————————
var fu;
function fn(fn){
console.log(fn);
}
fu=1;
console.log(fn(fn));
我不知道這樣解釋對不對。
因為當(dāng)函數(shù)和變量聲明前置,函數(shù)的聲明覆蓋了變量的聲明,最后1賦值給fu,這時候fu類型不是function而是number,這時候console.log(fn(fn)) 就報錯。顯示fn不是一個函數(shù)。
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
___________
此處沒有 什么變量提升,所以開始console.log(j);和console.log(i)都會報錯
然后經(jīng)過一個for循環(huán)后 i=10 j=100。
而且不會隨著循環(huán)的結(jié)束而消失,。然后console.log(i)和console.log(j) 就為10 和100
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;
}
}
------------
可轉(zhuǎn)換為:
var i
var fn
function fn(){
var i
function fn2(){
i = 100;
}
console.log(i);//undefined
i = 99;
fn2();
console.log(i);//100
}
fn();
i = 10;
fn = 20;
console.log(i);//10
前面直接跳過,到fn(),會執(zhí)行函數(shù)fn() 先聲明一個局部變量var.這里面開始并不會執(zhí)行fn2(){} 到console.log(i)。
因為這里i只是聲明了,并沒有定義,所有會得到undefined ;然后將99賦值給局部變量i.然后執(zhí)行fn2(),會得到一個變量I,由于沒有用var聲明,此處I 在fn()中有效,所有console.log(i)等于100。
然后將10賦值為變量i,20賦值給fn;
得到console.log(i) 為10.
10.如下代碼的輸出?為什么 (難度*****)
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
——————————
這里輸出10,9,8,7,6,5,4,3,2,0
因為函數(shù)為自執(zhí)行函數(shù),變量只在函數(shù)作用域內(nèi)生效,并不會影響到外面的變量。所以左后console.log(say)輸出0