函數(shù)參數(shù)傳遞的過(guò)程實(shí)際上就是實(shí)參像形參復(fù)制值的過(guò)程穗慕。
- 在向參數(shù)傳遞基本類型的值時(shí),被傳遞(實(shí)參)的值會(huì)復(fù)制給一個(gè)局部變量(形參),形參值的變化不會(huì)對(duì)函數(shù)外的實(shí)參產(chǎn)生影響忠蝗。
- 在向參數(shù)傳遞引用類型的值時(shí),會(huì)把這個(gè)值在內(nèi)存中的地址復(fù)制給形參滨溉。這時(shí)這個(gè)形參也指向了函數(shù)外的實(shí)參什湘,因此這個(gè)形參的變化也會(huì)導(dǎo)致實(shí)參的變化。
function addTen(num) {
num += 10;
return num;
}
var count = 20, result = addTen(count);
alert(count); //20
這里函數(shù) addTen()
的參數(shù)num
晦攒,實(shí)際上是函數(shù)的局部變量闽撤。在調(diào)用函數(shù)時(shí),變量count
作為參數(shù)傳遞給函數(shù)脯颜。由于 count
的值是20
哟旗,所以數(shù)值20
被復(fù)制給參數(shù)num
。在函數(shù)內(nèi)部栋操,這個(gè)參數(shù)被加了10
闸餐,但這并不會(huì)影響函數(shù)外部的count
變量。
當(dāng)向參數(shù)傳遞的值為對(duì)象時(shí)矾芙,例如:
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
person.name = "Greg";
setName(person);
alert(person.name); //"Nicholas"
這里首先是創(chuàng)建了一個(gè)對(duì)象舍沙,保存在變量person
中,并且給變量的 name
屬性賦值為 "Greg"
剔宪。然后這個(gè)變量被當(dāng)作參數(shù)傳遞給函數(shù)setName
的參數(shù) obj
拂铡。在函數(shù)內(nèi)部壹无,obj
和 person
指向同一個(gè)對(duì)象,因?yàn)閭鬟f的是對(duì)象的地址
感帅。所以給obj
的 name
屬性賦值后斗锭,也會(huì)改變 person
的name
屬性值。
如果在函數(shù)內(nèi)部為obj
新建一個(gè)對(duì)象實(shí)例失球,這個(gè)新對(duì)象實(shí)例會(huì)開辟新的內(nèi)存空間岖是,導(dǎo)致 obj
的地址和person
不同。此時(shí)实苞,obj
和 person
將指向兩個(gè)不同的對(duì)象豺撑,所以互不影響。例如:
function setName(obj) {
obj.name = "Nicholas"; // 這個(gè)obj和person指向的地址相同硬梁,即函數(shù)外person創(chuàng)建的對(duì)象前硫。
obj = new Object(); // 新建實(shí)例對(duì)象,導(dǎo)致obj指向另一個(gè)地址
obj.name = "Greg";
}
var person = new Object();
person.name = "Jhon";
setName(person);
alert(person.name); //"Nicholas"
全局上下文中的變量對(duì)象
全局對(duì)象(Global object
) 是在進(jìn)入任何執(zhí)行上下文之前就已經(jīng)創(chuàng)建了的對(duì)象荧止;這個(gè)對(duì)象只存在一份屹电,它的屬性在程序中任何地方都可以訪問(wèn),全局對(duì)象的生命周期終止于程序退出那一刻跃巡。
全局對(duì)象初始創(chuàng)建階段將Math
危号、String
、Date
素邪、parseInt
作為自身屬性外莲,等屬性初始化,同樣也可以有額外創(chuàng)建的其它對(duì)象作為屬性(其可以指向到全局對(duì)象自身)兔朦。例如偷线,在DOM
中,全局對(duì)象的window
屬性就可以引用全局對(duì)象自身(當(dāng)然沽甥,并不是所有的具體實(shí)現(xiàn)都是這樣):
global = {
Math: <...>,
String: <...>
...
...
window: global //引用自身
};
函數(shù)上下文中的變量對(duì)象
在函數(shù)執(zhí)行上下文中声邦,變量對(duì)象(VO
)是不能直接訪問(wèn)的,此時(shí)由活動(dòng)對(duì)象(activation object
,縮寫為AO
)扮演 VO
的角色摆舟。
活動(dòng)對(duì)象是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的亥曹,它通過(guò)函數(shù)的arguments
屬性初始化。arguments
屬性的值是 Arguments
對(duì)象:
Arguments
對(duì)象是活動(dòng)對(duì)象的一個(gè)屬性恨诱,它包括如下屬性:
-
callee
:指向當(dāng)前函數(shù)的引用媳瞪; -
length
: 真正傳遞的參數(shù)個(gè)數(shù); -
properties-indexes
(字符串類型的整數(shù)): 屬性的值就是函數(shù)的參數(shù)值(按參數(shù)列表從左到右排列)照宝。properties-indexes
內(nèi)部元素的個(gè)數(shù)等于arguments.length
蛇受,properties-indexes
的值和實(shí)際傳遞進(jìn)來(lái)的參數(shù)之間是共享的。
function foo(x, y, z) {
// 聲明的函數(shù)參數(shù)數(shù)量arguments (x, y, z)
alert(foo.length); // 3
// 真正傳進(jìn)來(lái)的參數(shù)個(gè)數(shù)(only x, y)
alert(arguments.length); // 2
// 參數(shù)的callee是函數(shù)自身
alert(arguments.callee === foo); // true
// 參數(shù)共享
alert(x === arguments[0]); // true
alert(x); // 10
arguments[0] = 20;
alert(x); // 20
x = 30;
alert(arguments[0]); // 30
// 不過(guò)厕鹃,沒(méi)有傳進(jìn)來(lái)的參數(shù)z龙巨,和參數(shù)的第3個(gè)索引值是不共享的
z = 40;
alert(arguments[2]); // undefined
arguments[2] = 50;
alert(z); // 40
}
foo(10, 20);
現(xiàn)在在嚴(yán)格模式下笼呆,
arguments
對(duì)象已與過(guò)往不同熊响。arguments
不再與函數(shù)的實(shí)際形參之間共享旨别,同時(shí)caller
屬性也被移除。
剩余參數(shù)汗茄、默認(rèn)參數(shù)和解構(gòu)賦值參數(shù)
在嚴(yán)格模式下秸弛,剩余參數(shù)、默認(rèn)參數(shù)和解構(gòu)賦值參數(shù)的存在不會(huì)改變 arguments
對(duì)象的行為洪碳,但是在非嚴(yán)格模式下就有所不同了递览。
當(dāng)非嚴(yán)格模式中的函數(shù)沒(méi)有包含剩余參數(shù)、默認(rèn)參數(shù)和解構(gòu)賦值瞳腌,那么arguments
對(duì)象中的值會(huì)跟蹤參數(shù)的值(反之亦然)绞铃。看下面的代碼:
function func(a) {
arguments[0] = 99; // 更新了arguments[0] 同樣更新了a
console.log(a);
}
func(10); // 99
并且
function func(a) {
a = 99; // 更新了a 同樣更新了arguments[0]
console.log(arguments[0]);
}
func(10); // 99
當(dāng)非嚴(yán)格模式中的函數(shù)有包含剩余參數(shù)嫂侍、默認(rèn)參數(shù)和解構(gòu)賦值儿捧,那么arguments
對(duì)象中的值不會(huì)跟蹤參數(shù)的值(反之亦然)√舫瑁看下面的代碼:
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
并且
function func(a = 55) {
console.log(arguments[0]);
}
func(); // undefined
delete
關(guān)于變量菲盾,還有一個(gè)重要的知識(shí)點(diǎn)。變量相對(duì)于簡(jiǎn)單屬性來(lái)說(shuō)各淀,變量有一個(gè)特性(attribute
):{ DontDelete
},這個(gè)特性的含義就是不能用 delete
操作符直接刪除變量屬性懒鉴。
a = 10;
alert(window.a); // 10
alert(delete a); // true
alert(window.a); // undefined
var b = 20;
alert(window.b); // 20
alert(delete b); // false
alert(window.b); // still 20
但是這個(gè)規(guī)則在有個(gè)上下文里不起走樣,那就是
eval
上下文碎浇,變量沒(méi)有 {DontDelete
} 特性临谱。
eval('var a = 10;');
alert(window.a); // 10
alert(delete a); // true
alert(window.a); // undefined
參考文章
Arguments 對(duì)象
深入理解JavaScript系列(12):變量對(duì)象(Variable Object)