函數(shù)表達(dá)式
var fn = function(){
var a = 1
console.log(a)
};
fn()
1
undefined
立即執(zhí)行函數(shù)
function(){
var a = 1
console.log(a)
}()
Uncaught SyntaxError
會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤的提示
javascript提供的執(zhí)行函數(shù)的語(yǔ)法
(function(){
var a = 1
console.log(a)
}())
1
undefined
函數(shù)會(huì)直接執(zhí)行吮铭,打出1
語(yǔ)句的返回值為undefined
除此之外时迫,還有其它的使用立即執(zhí)行函數(shù)的語(yǔ)法
(function(){
var a = 1
console.log(a)
})()
1
undefined
直接在函數(shù)添加前綴‘+’或‘-’
會(huì)在控制臺(tái)打出
1
NaN
前綴為‘~’
1
-1
前綴為‘!’
1
true
如果函數(shù)不是從第一行開(kāi)始,可能會(huì)出現(xiàn)錯(cuò)誤
var a = 2
(function(){
var a = 1
console.log(a)
})()
會(huì)出現(xiàn)未知錯(cuò)誤
上面提到的立即執(zhí)行函數(shù)
只有在函數(shù)前面添加前綴‘~’或‘!’
不會(huì)出現(xiàn)錯(cuò)誤
var a = 2
!function(){
var a = 1
console.log(a)
}()
1
true
按值傳遞和地址傳遞
!function outer(){
var outerA = 1
function inner(){
var innerA = 1
setInterval(function(){
innerA = innerA + 1
console.log("innerA的值是:" + innerA)
},1000)
var temp = {
ref:innerA //2
}
return temp
}
var tempRef = inner()
setInterval(function(){
console.log(tempRef)
},1000)
}()
innerA的值是:2
{ref: "2"}
innerA的值是:3
{ref: "2"}
. . . . . . . . . . . . . .//一秒打出一次
innerA是按值傳遞的沐兵。
上例中,可以看出在inner函數(shù)里的innerA便监,值是一直變化的
但是在執(zhí)行了inner函數(shù)之后返回的包含innerA的對(duì)象里
innerA的值卻是不變的扎谎。
因?yàn)閠empRef是只執(zhí)行了一次inner函數(shù)返回的值,
執(zhí)行時(shí)烧董,innerA的值是‘1’毁靶,
之后innerA的值再變化就和tempRef沒(méi)有關(guān)系了,
!function outer(){
var outerA = 1
function inner(){
var innerA = {name:1}
setInterval(function(){
innerA.name = innerA.name + 1
console.log("innerA的值是:" + innerA.name)
},1000)
var temp = {
ref:innerA //2
}
return temp
}
var tempRef = inner()
setInterval(function(){
console.log(JSON.stringify(tempRef))
},1000)
}()
innerA的值是:2
{"ref":{"name":2}}
innerA的值是:3
{"ref":{"name":3}}
. . . . . . . . . . . . . .//一秒打出一次
因?yàn)閕nnerA是按地址傳遞的
函數(shù)作用域鏈
這里簡(jiǎn)單介紹一下作用域
當(dāng)函數(shù)被調(diào)用時(shí)逊移,
會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境以及相應(yīng)的作用域鏈预吆。
在作用域鏈中,
函數(shù)內(nèi)的arguments和其它命名參數(shù)作為初始化函數(shù)的活動(dòng)對(duì)象胳泉,處于第一位拐叉。
外部函數(shù)的活動(dòng)對(duì)象處于第二位,
外部函數(shù)的外部函數(shù)的活動(dòng)對(duì)象處于第三位扇商,
直到作用域鏈重點(diǎn)的全局執(zhí)行環(huán)境凤瘦。
以compare()
函數(shù)為例
function compare(value1,value2){
if(value1<value2){
return -1;
} else if(value1>value2){
return 1;
} else {
return 0;
}
}
var result = compare(5,10)
執(zhí)行compare()
時(shí),
compare函數(shù)內(nèi)會(huì)創(chuàng)建一個(gè)包含arguments
數(shù)組案铺、value1
變量蔬芥、value2
變量的活動(dòng)對(duì)象。
因?yàn)槭窃谌肿饔糜蛑袌?zhí)行了函數(shù),
在全局作用域內(nèi)會(huì)創(chuàng)建一個(gè)包含result
變量笔诵、compare
函數(shù)的全局變量對(duì)象返吻。
在函數(shù)執(zhí)行之后,做產(chǎn)生一個(gè)作用域鏈乎婿,分別是全局作用域以及局部作用域测僵,在全局作用域里可獲取全局變量對(duì)象compare和result,在局部作用域里可獲取compare函數(shù)里的局部活動(dòng)變量對(duì)象arguments,value1,value2
什么是變量對(duì)象
后臺(tái)的每個(gè)執(zhí)行環(huán)境都有一個(gè)表示變量的對(duì)象——變量對(duì)象次酌。
全局環(huán)境的變量對(duì)象始終存在恨课,
函數(shù)的局部環(huán)境的變量對(duì)象只在執(zhí)行的過(guò)程中存在,執(zhí)行完之后就銷毀了岳服。
在創(chuàng)建compare()函數(shù)時(shí)剂公,
會(huì)創(chuàng)建一個(gè)預(yù)先包含全局變量對(duì)象的作用域鏈,在這個(gè)作用域鏈被保存在內(nèi)部的[[Scope]]屬性中吊宋。
調(diào)用函數(shù)時(shí)纲辽,
會(huì)為函數(shù)創(chuàng)建一個(gè)執(zhí)行環(huán)境,然后復(fù)制內(nèi)部屬性中的對(duì)象構(gòu)建執(zhí)行環(huán)境的作用域鏈璃搜。
同時(shí)拖吼,
有一個(gè)活動(dòng)對(duì)象被創(chuàng)建并推入執(zhí)行環(huán)境作用域鏈的前端。
這個(gè)作用域鏈中包含兩個(gè)變量對(duì)象:
本地活動(dòng)對(duì)象和全局變量對(duì)象这吻。
作用域鏈本質(zhì):
指向變量對(duì)象的指針列表吊档,只包含指針地址來(lái)對(duì)變量對(duì)象的引用。
函數(shù)內(nèi)的內(nèi)部函數(shù)會(huì)將它的外部函數(shù)的活動(dòng)對(duì)象添加進(jìn)它的作用域鏈唾糯。
探索閉包
閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)
創(chuàng)建閉包的常見(jiàn)方式怠硼,
就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù),
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[property];
var value2 = object2[property];
if(value1<value2){
return -1;
} else if(value1>value2){
return 1;
} else {
return 0;
}
}
}
執(zhí)行函數(shù)
var compare = createComparisonFunction("name");
//創(chuàng)建函數(shù)
var result = compare({name:"Jack"},{name:"Rose"});
//調(diào)用函數(shù)
compareNames = null
//解除對(duì)匿名函數(shù)的引用(以便釋放內(nèi)存)