函數聲明和函數表達式有什么區(qū)別?
函數聲明和函數表達式是EMACScript規(guī)定的兩種不同的聲明函數的方法刀疙。
1.函數聲明
//聲明函數
function name() { //function+函數名+(參數)+{函數體}
console.log ('Jack')
}
//函數調用
name()
函數聲明會在JavaScript代碼開始時提到最前面進行定義舶赔,因此函數聲明不必在調用之前定義。
2.函數表達式
var name = function () {
console.log ('Jack')
}
雖然變量聲明會提到JavaScript代碼開始前谦秧,但是賦值要運行到該行代碼才執(zhí)行竟纳,因此在調用用函數表達式聲明的函數時,聲明必須放到調用前疚鲤。
總結區(qū)別:
1.函數聲明會在代碼開始前定義锥累,函數表達式遇到時才會執(zhí)行。
2.函數聲明必須有函數名集歇,函數表達式則可以省略桶略。
什么是變量的聲明前置?什么是函數的聲明前置诲宇?
- 變量的聲明前置:
在一個作用域塊中际歼,所有的變量聲明都會被JS引擎放在作用域塊范圍的頂部進行聲明;
- 函數的聲明前置:
和變量聲明前置一樣姑蓝,執(zhí)行代碼之前會先讀取函數聲明鹅心,只要函數在代碼中進行了聲明,無論它在作用域塊的哪個位置上進行聲明纺荧,JS引擎都會將它的聲明放在作用域塊范圍的頂部進行聲明旭愧;
arguments是什么?
在ECMAScript中,函數的參數在內部是用一個數組來表示的宙暇。在函數體內榕茧,可以用arguments來訪問這個參數數組。arguments是一個類數組對象(不是Array的實例)客给,因為可以使用方括號語法訪問它的每一個元素用押,使用length屬性來確定傳遞進來多少參數,示例:
function test () {
console.log (arguments.length); //參數的長度
console.log (arguments[0]); //第一個參數
console.log (arguments[1]); //第二個參數
}
test ('Jack',1,'888');
//輸出結果為 3靶剑,'Jack'蜻拨,1
JS函數的"重載"怎樣實現?
重載桩引,是函數或者方法有相同的名稱缎讼,但是參數列表不相同的情形,這樣的同名不同參數的函數或者方法之間坑匠,互相稱之為重載函數或者方法血崭。但是在JS,并沒有重載這個概念,但我們可以用另外一種方法實現這個功能:
function test (num) {
if (num>=90) {
console.log ('優(yōu)秀')
}
if (num>=60&&num<90) {
console.log ('及格')
}
if (num<60) {
console.log ('不及格')
}
}
test(95) //輸出 '優(yōu)秀'
test(77) //輸出 '及格'
test(18) //輸出 '不及格'
這樣對于同一個函數夹纫,輸入不同參數就會得到不同結果咽瓷。
立即執(zhí)行函數表達式是什么?有什么作用舰讹?
在JS中我們可以使用函數聲明和函數表達式聲明函數茅姜,再通過函數名進行調用:
function sayName (name) { //函數聲明聲明函數
console.log (name);
}
sayName ('Jack'); // 調用函數
var sayName = function () { //函數表達式聲明函數
console.log (name);
}
sayName ('Jack') // 調用函數
因為在JS中圓括號()內是不能有語句的,括號內容會被當做表達式月匣,因此上面例子可以進行改寫:
(function (name) {
console.log (name);
})('Jack')
//或者
(function (name) {
console.log (name);
}('Jack')) // 輸出都為Jack
當JS執(zhí)行到該行代碼時钻洒,函數會被定義且立即執(zhí)行,叫做立即執(zhí)行函數表達式锄开。使用立即執(zhí)行函數表達式可以創(chuàng)建一個獨立的作用域素标,形成隔離,避免污染全局萍悴。
求n!头遭,用遞歸來實現
ffunction multiply(n){
if(n===1){
return 1;
}
return n*multiply(n-1);
}
multiply(3);//6
以下代碼輸出什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments); //輸出整組參數退腥;
arguments[0] = 'valley'; //第一個參數賦值為‘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添寺;
寫一個函數胯盯,返回參數的平方和
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(result) //10
解釋下列代碼的輸出及原因
console.log(a); // 由于聲明提前,此時a未賦值计露,輸出undefined博脑;
var a = 1; // a=1;
console.log(b); //報錯憎乙,b未被聲明;
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);
}
var sayAge;
sayName('world'); //調用函數叉趣,輸出'hello泞边,world';
sayAge(10); //undefined,因為sayAge未定義君账;
sayAge = function(age){
console.log(age);
};
//函數表達式需放到調用前7北ぁ沈善!
如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
} // 輸出 10乡数;
/*作用域查找過程
goblecontext = {
AO: {
X=10
foo: function
bar: function
}
foo.[[scope]]: goblecontext.AO
bar.[[scope]]: goblecontext.AO
}
foocontext = {
AO: {}
scope: goblecontext.AO
}
barcontext = {
AO: {
x = 30
}
scope: goblecontext.AO
}*/
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
} //輸出30
/*作用域查找過程
goblecontext = {
AO: {
x=10
bar:function
}
bar.[[scopr]]=goblecontext.AO
}
barcontext = {
AO: {
x=30
foo:function
}
foo.[[scope]]=barcontext.AO
scope=goblecontext.AO
}
foocontext = {
AO: {}
scope=barcontext.AO
}*/
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
} //輸出30
/*作用域查找
goblecontext = {
AO: {
x=10
bar:function
}
bar.[[scope]]=goblecontext.AO
scope=null
}
barcontext = {
AO: {
x=30
f:function
}
f.[[scope]]=barcontext.AO
scope=goblecontext.AO
}
fcontext = {
AO: {}
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() //輸出:undefined,5闻牡,1净赴,6,20罩润,200玖翅;
console.log(a)
/*
goblecontext = {
AO: {
a: undefined
fn: function
fn3: function
}
scope = null
fn.[[scope]] = goblecontext.AO
fn3.[[scope]] = goblecontext.AO
}
fncontext = {
AO: {
a: undefinef
fn2: function
}
scope = goblecontext.AO
fn2.[[scope]] = fncontext.AO
}
fn2context = {
AO: {
a: 20
}
scope = fncontext.AO
}
fn3context = {
AO: {
a: 200
}
scope = goblecontext.AO
}*/
遇到fn(),開始執(zhí)行:
console.log(a),,此時fncontextAO中a未被賦值割以,輸出undefined金度;
a = 5;
console.log(a),此時fncontextAO中a被賦值為5严沥,輸出5猜极;
a++,fncontextAO中a變?yōu)?消玄;
var a跟伏,因為a已經存在,故無意義翩瓜;
fn3()受扳,執(zhí)行fn3(),進入fn3context兔跌;
console.log(a)勘高,goblecontextAO中,a=1坟桅,故輸出1华望;
a=200,goblecontextAO中a變?yōu)?00桦卒;
fn2立美,執(zhí)行fn2(),進入fn2context方灾;
console.log(a)建蹄,fncontextAO中碌更,a=6,故輸出6洞慎;
a=20痛单,fncontextAO中,a變?yōu)?0劲腿;
console.log(a)旭绒,fncontextAO中,a為20焦人,故輸出20挥吵;
fn執(zhí)行完畢;
console.log(a)花椭,goblecontextAO中忽匈,a為200,故輸出200矿辽;