一莫其、問答
函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別?
Js中的函數(shù)聲明是指下面的形式:
function functionName() {
alert("Hello");
}
函數(shù)表達(dá)式則是類似表達(dá)式那樣來聲明一個(gè)函數(shù)颂砸,如:
var functionName = function() {
alert("Hello");
}
functionName();
js的解析器對函數(shù)聲明與函數(shù)表達(dá)式并不是一視同仁地對待的夸浅。
對于函數(shù)聲明,js解析器會優(yōu)先讀取朴则,確保在所有代碼執(zhí)行之前聲明已經(jīng)被解析;
而函數(shù)表達(dá)式匙赞,如同定義其它基本類型的變量一樣佛掖,只在執(zhí)行到某一句時(shí)也會對其進(jìn)行解析。
所以在實(shí)際中涌庭,它們還是會有差異的芥被,具體表現(xiàn)在,當(dāng)使用函數(shù)聲明的形式來定義函數(shù)時(shí)坐榆,可將調(diào)用語句寫在函數(shù)聲明之前拴魄,而后者,這樣做的話會報(bào)錯(cuò)席镀。
什么是變量的聲明前置匹中?什么是函數(shù)的聲明前置?
變量聲明前置:javascript的變量聲明具有hoisting機(jī)制豪诲,JavaScript引擎在執(zhí)行的時(shí)候顶捷,只要變量在代碼中進(jìn)行了聲明,無論它在哪個(gè)位置上進(jìn)行聲明屎篱, js引擎都會將它的聲明放在范圍作用域的頂部服赎。
console.log(a); //這個(gè)時(shí)候的輸出結(jié)果為undefined,因?yàn)槁暶鞅磺爸昧怂圆粫?bào)錯(cuò)
var a = 1;
/*等同于:*/
var a;
console.log(a);
a = 1;
函數(shù)聲明前置:和變量聲明前置一樣交播,因hoisting機(jī)制重虑,執(zhí)行代碼之前會先讀取函數(shù)聲明,只要函數(shù)在代碼中進(jìn)行了聲明秦士,無論它在哪個(gè)位置上進(jìn)行聲明缺厉, js引擎都會將它的聲明放在范圍作用域的頂部。意味著可以把函數(shù)申明放在調(diào)用它的語句后面隧土,但是函數(shù)表達(dá)式不行提针。
sayHi(); //此處輸出結(jié)果“hi”,因?yàn)楹瘮?shù)生命被前置了所以能正常調(diào)用
sayName(); //報(bào)錯(cuò)次洼。僅僅是表達(dá)式里的變量sayName被前置了关贵,此時(shí)未解析到函數(shù)
function sayHi() {
console.log("hi");
}
var sayName = function() {
console.log("Amy");
}
arguments 是什么?
arguments 是是JavaScript里的一個(gè)內(nèi)置對象卖毁,所有的函數(shù)都有屬于自己的一個(gè)arguments對象揖曾,它包括了函所有調(diào)用的參數(shù),條目索引從 0 開始亥啦。他不是一個(gè)數(shù)組炭剪,如果用typeof arguments,返回的是'object'翔脱。
function myArray() {
console.log(arguments[2]); //輸出30
}
myArray(10,20,30);
函數(shù)的重載怎樣實(shí)現(xiàn)奴拦?
JS函數(shù)沒有重載這個(gè)概念,相同函數(shù)重復(fù)聲明時(shí)届吁,后面覆蓋前面的错妖。
但每一個(gè)函數(shù)都有一個(gè)特殊的參數(shù)arguments绿鸣,可以通過它傳遞參數(shù)個(gè)數(shù)來實(shí)現(xiàn)不同效果。
<script type="text/javascript">
function add() {
if (arguments.length == 1) {
alert(arguments[0] + 10);
}
else if (arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
//函數(shù)調(diào)用
add(10);
add(10, 20);
</script>
立即執(zhí)行函數(shù)表達(dá)式是什么暂氯?有什么作用潮模?
//方法一:
(function myFunction() {
}()
)
//方法二:
(function myFunction() {
}
)()
用立即執(zhí)行函數(shù)處理模塊化可以減少全局變量造成的空間污染,構(gòu)造更多的私有變量痴施。
什么是函數(shù)的作用域鏈擎厢?
任何程序設(shè)計(jì)語言都有作用域的概念,簡單的說辣吃,作用域就是變量與函數(shù)的可訪問范圍动遭,即作用域控制著變量與函數(shù)的可見性和生命周期。在JavaScript中神得,變量的作用域有全局作用域和局部作用域兩種厘惦。
全局作用域:在代碼中任何地方都能訪問到的對象擁有全局作用域。
- 最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域循头;
- 所有末定義直接賦值的變量自動聲明為擁有全局作用域绵估;
- 所有window對象的屬性擁有全局作用域,例如:window.name卡骂、window.location国裳、window.top等等。
局部作用域:和全局作用域相反全跨,局部作用域一般只在固定的代碼片段內(nèi)可訪問到缝左,最常見的例如函數(shù)內(nèi)部,所以在一些地方也會看到有人把這種作用域稱為函數(shù)作用域浓若。
當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí)渺杉,會創(chuàng)建變量對象的的一個(gè)作用域鏈(scope chain)。作用域鏈的用途挪钓,是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問是越。作用域鏈的前端,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對象碌上。如果這個(gè)環(huán)境是一個(gè)函數(shù)倚评,則將其活動對象作為變量對象。
每一個(gè)函數(shù)都有自己的執(zhí)行環(huán)境馏予,當(dāng)執(zhí)行流進(jìn)一個(gè)函數(shù)時(shí)天梧,函數(shù)環(huán)境就會被推入一個(gè)環(huán)境棧中,而在函數(shù)執(zhí)行之后霞丧,棧將其環(huán)境彈出呢岗,把控制權(quán)返回給之前的執(zhí)行環(huán)境,這個(gè)棧也就是作用域鏈。
二后豫、代碼
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('男');
輸出:
name: hunger
age: 28
sex: 男
["hunger", 28, "男"]
name valley
name: hunger
age: 28
sex: undefined
["hunger", 28]
name valley
name: 男
age: undefined
sex: undefined
[男]
name valley
2.寫一個(gè)函數(shù),返回參數(shù)的平方和挫酿?
function sumOfSquares(){
var sum=0;
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); //undefined 因?yàn)樽兞柯暶鳌皏ar a”被前置
var a = 1;
console.log(b); //報(bào)錯(cuò) 因?yàn)椤癰”未被聲明
4.如下代碼的輸出?為什么饭豹?
sayName('world'); //hello world 因?yàn)楹瘮?shù)聲明會被前置,所以調(diào)用語句寫在函數(shù)聲明之前也是可以正常調(diào)用的
sayAge(10); //報(bào)錯(cuò) 因?yàn)楹瘮?shù)表達(dá)式不會被前置务漩,此處未解析到函數(shù)
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
5.如下代碼的輸出拄衰?為什么?
function fn(){}
var fn = 3;
console.log(fn); //輸出3
//等同于:
var fn;
function fn(){}
fn = 3;
console.log(fn);
6.如下代碼的輸出?為什么?
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
//等同于:
function fn(fn2){
var fn2; //變量提升
function fn2(){
console.log('fnnn2');
} //函數(shù)聲明前置
console.log(fn2); //打印函數(shù)fn2
fn2 = 3;
console.log(fn2); //3
console.log(fn); //打印整個(gè)fn函數(shù)。在內(nèi)部作用域內(nèi)沒找到fn啤挎,所以往父級找欣尼,找到fn這個(gè)函數(shù)
}
fn(10);
//結(jié)果:
function fn2(){
console.log('fnnn2');
}
3
fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
7.如下代碼的輸出?為什么少漆?
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
//等同于:
var fn; //變量聲明前置
function fn(fn){
console.log(fn);
};
fn = 1; //給fn值為1
console.log(fn(fn)); //報(bào)錯(cuò) 因?yàn)榇藭r(shí)fn已經(jīng)不是一個(gè)函數(shù)
8.如下代碼的輸出?為什么?
console.log(j); //undefined 變量聲明被前置制市,還未被賦值
console.log(i); //undefined 變量聲明被前置,還未被賦值
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i); //10 循環(huán)結(jié)束時(shí)i的值為10
console.log(j); //100 j被賦值為100
//注:只有函數(shù)才具有作用域弊予,上面代碼的for循環(huán)里的變量屬于全局變量會被提升到頂部祥楣。
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;
}
}
//實(shí)際順序?yàn)椋?
var i; //變量提升
var fn; //變量提升
function fn(){ //函數(shù)聲明提升
var i; //作用域內(nèi)變量提升
function fn2(){ //作用域內(nèi)函數(shù)聲明提升
i = 100;
}
console.log(i); //undefined i還沒被賦值
i = 99;
fn2();
console.log(i); //100 i被賦值為100
}
i = 10; //i賦值為10
fn = 20;
console.log(i); //10
如下代碼的輸出误褪?為什么?
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 )); //n初始為10碾褂,立即執(zhí)行函數(shù)輸出10,9,8,7,6,5,4,3,2兽间,小于3停止循環(huán)
console.log(say); //0 因?yàn)榱⒓磮?zhí)行函數(shù)創(chuàng)造了私有作用域,外部不能訪問內(nèi)部變量正塌,所以此處say為0
本教程版權(quán)歸作者和饑人谷所有嘀略,轉(zhuǎn)載須說明來源!