1 . 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
函數(shù)聲明:
function name(param1, param2, ..., paramN){
statements;
}
使用function關(guān)鍵字聲明一個(gè)函數(shù)恶复,再指定一個(gè)函數(shù)名怜森,叫函數(shù)聲明。此函數(shù)能實(shí)現(xiàn)聲明前置谤牡,函數(shù)的調(diào)用可以在任意位置副硅,即聲明前和聲明后調(diào)用均可。
函數(shù)表達(dá)式:
function [name](param1, param2, ..., paramN) {
statements;
}
函數(shù)表達(dá)式非常類似于函數(shù)聲明翅萤,并且擁有幾乎相同的語(yǔ)法恐疲。函數(shù)表達(dá)式與函數(shù)聲明的最主要區(qū)別是函數(shù)名稱,在函數(shù)表達(dá)式中可忽略它套么,從而創(chuàng)建匿名函數(shù)的方式來(lái)聲明一個(gè)函數(shù)培己。
聲明前置的是接收函數(shù)指針的變量,而不是函數(shù)本身胚泌,所以必須將聲明放在調(diào)用前面省咨。
2 . 什么是聲明前置
瀏覽器在解析JavaScript代碼時(shí),會(huì)將所有的變量聲明和函數(shù)聲明提升到它們當(dāng)前的作用域的最前面玷室。
全局作用域和函數(shù)作用域下分別實(shí)現(xiàn)各自的聲明前置零蓉。
當(dāng)發(fā)生變量和函數(shù)重名時(shí),先前置阵苇,后覆蓋壁公。
3 . 求n!,用遞歸來(lái)實(shí)現(xiàn)
function f(n){
if (n == 1){
return 1;
}
return n * f(n-1);
}
4 . 什么是立即執(zhí)行的函數(shù)表達(dá)式绅项?有什么作用紊册?
立即執(zhí)行的函數(shù)表達(dá)式:使用某種運(yùn)算方式將函數(shù)變成一個(gè)表達(dá)式,立即得到函數(shù)的結(jié)果快耿,完成函數(shù)調(diào)用囊陡。
實(shí)現(xiàn)方式:
- 用
()
包裹函數(shù),得到函數(shù)表達(dá)式的一個(gè)結(jié)果---函數(shù)名掀亥,然后使用函數(shù)名調(diào)用函數(shù)撞反。因?yàn)樵趈avascript里,括號(hào)內(nèi)部不能包含語(yǔ)句搪花,當(dāng)解析器對(duì)代碼進(jìn)行解釋的時(shí)候遏片,先碰到了()嘹害,然后碰到function關(guān)鍵字就會(huì)自動(dòng)將()里面的代碼識(shí)別為函數(shù)表達(dá)式而不是函數(shù)聲明
(function(){
var a = 1;
})();
或則
(function(){
var a = 1;
}());
- 使用
[]
或則,
或則&&
運(yùn)算符
// 在數(shù)組初始化器內(nèi)只能是表達(dá)式
[function fn2() {}];
// 逗號(hào)也只能操作表達(dá)式
1, function fn3() {};
//` && `兩邊也是表達(dá)式
true && function () { /* code */ } ();
- 使用一元運(yùn)算符得到立即執(zhí)行函數(shù)表達(dá)式
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
作用:利用函數(shù)作用域下吮便,變量用完即釋放的功能笔呀,來(lái)實(shí)現(xiàn)隔離作用域,污染防止全局變量的效果髓需。
5 . 如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10;
bar();
function foo() {
console.log(x);
}
function bar(){
var x = 30;
foo(); // 輸出什么
}
foo(); // 輸出10
作用域鏈查找過(guò)程偽代碼:
globalContext = {
AO:{
x: 10,
foo: function,
bar: function,
},
Scope: null,
}
//在當(dāng)前的執(zhí)行上下文內(nèi)聲明的函數(shù)许师,這個(gè)函數(shù)的[[scope]]就是當(dāng)前執(zhí)行上下文
//調(diào)用函數(shù)的時(shí)候進(jìn)入到函數(shù)的執(zhí)行上下文
fooContext.Scope = globalContext;
barContext.Scope = globalContext;
fooContext = {
AO:{
},
Scope: globalContext,
}
barContext = {
AO:{
x: 30,
},
Scope: globalContext,
}
6 . 如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10;
bar() // 輸出什么
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
bar() // 輸出30
作用域鏈查找過(guò)程偽代碼:
globalContext = {
AO:{
x: 10,
bar: function,
},
Scope: null,
}
barContext.Scope = globalContext;
barContext = {
AO:{
x: 30,
foo: function,
},
Scope: globalContext,
}
fooContext.Scope = barContext;
fooContext = {
AO:{
},
Scope: barContext,
}
7 . 一下代碼輸出什么? 寫(xiě)出作用域鏈的查找過(guò)程偽代碼
var x = 10;
bar() // 輸出什么
function bar(){
var x = 30;
(function (){ console.log(x) })();
}
bar() // 輸出30
作用域鏈查找過(guò)程偽代碼:
globalContext = {
AO:{
x: 10,
bar: function,
},
Scope: null,
}
barContext.Scope = globalContext;
barContext = {
AO:{
x: 30,
(function(){}): funtion,
},
Scope: globalContext,
}
(function(){}).Scope = barContext;
(function(){})Context = {
AO:{
},
Scope: barContext,
}
8.以下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
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);
輸出:undefined 5 1 6 20 200
作用域鏈查找過(guò)程偽代碼:
1.
globalContext = {
AO:{
a: 1,
fn: function,
fn3: function,
},
Scope: null,
}
fnContext.Scope = globalContext;
fn3Context.Scope = globalContext;
fnContext = {
AO:{
a: undefined,//fn第一個(gè)console.log(a)
fn2: funtion,
},
Scope: globalContext.AO,
}
fn2Context.Scope = fnContext;
fn2Context = {
AO:{
},
Scope: fnContext,
}
fn3Context = {
AO:{
},
Scope: globalContext,
}
2.
fnContext = {
AO:{
a: 5,//fn第二個(gè)console.log(a)
fn2: funtion,
},
Scope: globalContext,
}
3.
globalContext = {
AO:{
a: 1,//fn3的console.log(a)
fn: function,
fn3: function,
},
Scope: null,
}
fnContext = {
AO:{
a: 6,//a++之后
fn2: funtion,
},
Scope: globalContext,
}
fn3Context = {
AO:{
},
Scope: globalContext,
}
4.
globalContext = {
AO:{
a: 200,//fn3的a = 200
fn: function,
fn3: function,
},
Scope: null,
}
fnContext = {
AO:{
a: 6,//fn2的console.log(a)
fn2: funtion,
},
Scope: globalContext,
}
fn2Context = {
AO:{
},
Scope: fnContext,
}
fn3Context = {
AO:{
},
Scope: globalContext,
}
5.
fnContext = {
AO:{
a: 20,//fn2里a = 20;fn的第三個(gè)console.log(a)
fn2: funtion,
},
Scope: globalContext,
}
6.
globalContext = {
AO:{
a: 200,//全局最后的console.log(a)
fn: function,
fn3: function,
},
Scope: null,
}
9.以下代碼輸出什么僚匆?畫(huà)出執(zhí)行過(guò)程作用域偽代碼(難度五顆星微渠,用興趣的同學(xué)可選做)
function fn(){
var x = 1;
function fn2(){
x++;
console.log(x) ;
}
return fn2;
}
var foo = fn();
var bar = fn();
foo();
bar();
foo();
輸出:2 2 3
作用域鏈查找過(guò)程偽代碼:
globalContext = {
AO:{
fn: function,
foo: function,//fn2
bar: function,//fn2
},
Scope: null,
}
fnContext.Scope = globalContext;
fooContext.Scope = globalContext;
barContext.Scope = globalContext;
fnContext = {
AO: {
x: 1,
fn2: function,
}
Scope: globalContext;
}
fn2Context.Scope = fnContext;
fn2Context = {
AO: {
}
Scope: fnContext;
}
//首先,foo和bar是兩個(gè)不同的變量咧擂,占用不同的內(nèi)存資源逞盆,是兩個(gè)獨(dú)立的實(shí)例,互不影響屋确。
1.foo();
fooContext = {
AO: {
}
//foo的Scope具有g(shù)lobalContext和fnContext雙重屬性
Scope: fnContext,
globalContext,
}
fnContext = {
AO: {
x: 2,//x++后
fn2: function,
}
Scope: globalContext;
}
2.bar();
barContext = {
AO: {
}
//bar的Scope具有g(shù)lobalContext和fnContext雙重屬性纳击,且和foo的Scope互不影響
Scope: fnContext,
globalContext,
}
fnContext = {
AO: {
x: 2,//x++后
fn2: function,
}
Scope: globalContext,
}
3.foo();
fooContext = {
AO: {
}
//foo的Scope具有g(shù)lobalContext和fnContext雙重屬性
Scope: fnContext,
globalContext,
}
fnContext = {
AO: {
x: 3,//x++后
fn2: function,
}
Scope: globalContext,
}