函數(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
會出現(xiàn)語法錯誤的提示
javascript提供的執(zhí)行函數(shù)的語法
(function(){
var a = 1
console.log(a)
}())
1
undefined
函數(shù)會直接執(zhí)行,打出1
語句的返回值為undefined
除此之外,還有其它的使用立即執(zhí)行函數(shù)的語法
(function(){
var a = 1
console.log(a)
})()
1
undefined
直接在函數(shù)添加前綴‘+’或‘-’
會在控制臺打出
1
NaN
前綴為‘~’
1
-1
前綴為‘!’
1
true
如果函數(shù)不是從第一行開始,可能會出現(xiàn)錯誤
var a = 2
(function(){
var a = 1
console.log(a)
})()
會出現(xiàn)未知錯誤
上面提到的立即執(zhí)行函數(shù)
只有在函數(shù)前面添加前綴‘~’或‘!’
不會出現(xiàn)錯誤
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的對象里
innerA的值卻是不變的。
因為tempRef是只執(zhí)行了一次inner函數(shù)返回的值,
執(zhí)行時,innerA的值是‘1’,
之后innerA的值再變化就和tempRef沒有關(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}}
. . . . . . . . . . . . . .//一秒打出一次
因為innerA是按地址傳遞的
函數(shù)作用域鏈
這里簡單介紹一下作用域
當(dāng)函數(shù)被調(diào)用時,
會創(chuàng)建一個執(zhí)行環(huán)境以及相應(yīng)的作用域鏈。
在作用域鏈中,
函數(shù)內(nèi)的arguments和其它命名參數(shù)作為初始化函數(shù)的活動對象,處于第一位。
外部函數(shù)的活動對象處于第二位,
外部函數(shù)的外部函數(shù)的活動對象處于第三位,
直到作用域鏈重點的全局執(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()
時,
compare函數(shù)內(nèi)會創(chuàng)建一個包含arguments
數(shù)組、value1
變量、value2
變量的活動對象。
因為是在全局作用域中執(zhí)行了函數(shù),
在全局作用域內(nèi)會創(chuàng)建一個包含result
變量、compare
函數(shù)的全局變量對象。
在函數(shù)執(zhí)行之后,做產(chǎn)生一個作用域鏈,分別是全局作用域以及局部作用域,在全局作用域里可獲取全局變量對象compare和result,在局部作用域里可獲取compare函數(shù)里的局部活動變量對象arguments,value1,value2
什么是變量對象
后臺的每個執(zhí)行環(huán)境都有一個表示變量的對象——變量對象。
全局環(huán)境的變量對象始終存在,
函數(shù)的局部環(huán)境的變量對象只在執(zhí)行的過程中存在,執(zhí)行完之后就銷毀了。
在創(chuàng)建compare()函數(shù)時,
會創(chuàng)建一個預(yù)先包含全局變量對象的作用域鏈,在這個作用域鏈被保存在內(nèi)部的[[Scope]]屬性中。
調(diào)用函數(shù)時,
會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,然后復(fù)制內(nèi)部屬性中的對象構(gòu)建執(zhí)行環(huán)境的作用域鏈。
同時,
有一個活動對象被創(chuàng)建并推入執(zhí)行環(huán)境作用域鏈的前端。
這個作用域鏈中包含兩個變量對象:
本地活動對象和全局變量對象。
作用域鏈本質(zhì):
指向變量對象的指針列表,只包含指針地址來對變量對象的引用。
函數(shù)內(nèi)的內(nèi)部函數(shù)會將它的外部函數(shù)的活動對象添加進(jìn)它的作用域鏈。
探索閉包
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)
創(chuàng)建閉包的常見方式,
就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(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
//解除對匿名函數(shù)的引用(以便釋放內(nèi)存)