JS中的變量對象

函數(shù)參數(shù)傳遞的過程實(shí)際上就是實(shí)參像形參復(fù)制值的過程。

  • 在向參數(shù)傳遞基本類型的值時(shí),被傳遞(實(shí)參)的值會(huì)復(fù)制給一個(gè)局部變量(形參),形參值的變化不會(huì)對函數(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ù)傳遞的值為對象時(shí),例如:

 function setName(obj) {
    obj.name = "Nicholas";
  }

  var person = new Object();
  person.name = "Greg";
  setName(person);
  alert(person.name);  //"Nicholas"

這里首先是創(chuàng)建了一個(gè)對象,保存在變量person中,并且給變量的 name屬性賦值為 "Greg"。然后這個(gè)變量被當(dāng)作參數(shù)傳遞給函數(shù)setName的參數(shù) obj。在函數(shù)內(nèi)部,objperson 指向同一個(gè)對象,因?yàn)閭鬟f的是對象的地址。所以給objname屬性賦值后,也會(huì)改變 personname屬性值。

如果在函數(shù)內(nèi)部為obj新建一個(gè)對象實(shí)例,這個(gè)新對象實(shí)例會(huì)開辟新的內(nèi)存空間,導(dǎo)致 obj的地址和person不同。此時(shí),objperson 將指向兩個(gè)不同的對象,所以互不影響。例如:

  function setName(obj) {
    obj.name = "Nicholas"; // 這個(gè)obj和person指向的地址相同,即函數(shù)外person創(chuàng)建的對象。    
    obj = new Object(); // 新建實(shí)例對象,導(dǎo)致obj指向另一個(gè)地址    
    obj.name = "Greg";
  }

  var person = new Object();
  person.name = "Jhon";
  setName(person);
  alert(person.name); //"Nicholas"

全局上下文中的變量對象

全局對象(Global object) 是在進(jìn)入任何執(zhí)行上下文之前就已經(jīng)創(chuàng)建了的對象;這個(gè)對象只存在一份,它的屬性在程序中任何地方都可以訪問,全局對象的生命周期終止于程序退出那一刻。

全局對象初始創(chuàng)建階段將Math、String、Date、parseInt 作為自身屬性,等屬性初始化,同樣也可以有額外創(chuàng)建的其它對象作為屬性(其可以指向到全局對象自身)。例如,在DOM中,全局對象的window屬性就可以引用全局對象自身(當(dāng)然,并不是所有的具體實(shí)現(xiàn)都是這樣):

global = {
  Math: <...>,
  String: <...>
  ...
  ...
  window: global //引用自身
};

函數(shù)上下文中的變量對象

在函數(shù)執(zhí)行上下文中,變量對象(VO)是不能直接訪問的,此時(shí)由活動(dòng)對象(activation object,縮寫為AO)扮演 VO 的角色。

活動(dòng)對象是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的,它通過函數(shù)的arguments屬性初始化。arguments屬性的值是 Arguments對象:

Arguments 對象是活動(dòng)對象的一個(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)來的參數(shù)之間是共享的。
function foo(x, y, z) {
 
  // 聲明的函數(shù)參數(shù)數(shù)量arguments (x, y, z)
  alert(foo.length); // 3
 
  // 真正傳進(jìn)來的參數(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
 
  // 不過,沒有傳進(jìn)來的參數(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 對象已與過往不同。arguments 不再與函數(shù)的實(shí)際形參之間共享,同時(shí)caller屬性也被移除。

剩余參數(shù)、默認(rèn)參數(shù)和解構(gòu)賦值參數(shù)

在嚴(yán)格模式下,剩余參數(shù)、默認(rèn)參數(shù)和解構(gòu)賦值參數(shù)的存在不會(huì)改變 arguments對象的行為,但是在非嚴(yán)格模式下就有所不同了。

當(dāng)非嚴(yán)格模式中的函數(shù)沒有包含剩余參數(shù)、默認(rèn)參數(shù)和解構(gòu)賦值,那么arguments對象中的值會(huì)跟蹤參數(shù)的值(反之亦然)??聪旅娴拇a:

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對象中的值不會(huì)跟蹤參數(shù)的值(反之亦然)??聪旅娴拇a:

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)。變量相對于簡單屬性來說,變量有一個(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上下文,變量沒有 { DontDelete } 特性。

eval('var a = 10;');
alert(window.a); // 10
 
alert(delete a); // true
 
alert(window.a); // undefined

參考文章

Arguments 對象
深入理解JavaScript系列(12):變量對象(Variable Object)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,926評(píng)論 0 5
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,504評(píng)論 0 13
  • 曾幾何時(shí) 伴著夜的來臨,是夜蟲的奏鳴 沒有華麗的光,也沒有喧囂的鬧 自從有了夜燈 路就不會(huì)寂寞 燈亮,在你轉(zhuǎn)身的瞬...
    無論波濤閱讀 679評(píng)論 0 0
  • 踐行許多天了都沒有做到詩文上墻,今天在單位專門打出一首準(zhǔn)備回家上墻。至于打哪一首糾結(jié)了半天,選了《春曉》,因?yàn)橛X得...
    夏更幽閱讀 318評(píng)論 0 0
  • 無論我在何方 心里裝的 永遠(yuǎn)都是你 地球是圓的 所以無論你走的多遠(yuǎn) 都要回到原點(diǎn) 我不管你走的多遠(yuǎn) 也不管你走了多...
    江瀟然閱讀 351評(píng)論 0 5

友情鏈接更多精彩內(nèi)容