JavaScript的值傳遞和引用傳遞

譯者按: 機智如你,應(yīng)該可以答對文末的面試題吧?如果不能,請好好學(xué)習(xí),天天編程:)

為了保證可讀性死姚,本文采用意譯而非直譯。另外勤篮,本文版權(quán)歸原作者所有都毒,翻譯僅用于學(xué)習(xí)。

JavaScript有5種基本的數(shù)據(jù)類型碰缔,分別是:布爾账劲、null、undefined金抡、String和Number瀑焦。這些基本類型在賦值的時候是通過值傳遞的方式。值得注意的是還有另外三種類型: Array梗肝、Function和Object榛瓮,它們通過引用來傳遞。從底層技術(shù)上看巫击,它們?nèi)际菍ο蟆?/p>

基本數(shù)據(jù)類型

如果一個基本的數(shù)據(jù)類型綁定到某個變量禀晓,我們可以認(rèn)為該變量包含這個基本數(shù)據(jù)類型的值。

var x = 10;
var y = 'abc';
var z = null;

當(dāng)我們使用=將這些變量賦值到另外的變量坝锰,實際上是將對應(yīng)的值拷貝了一份粹懒,然后賦值給新的變量。我們把它稱作值傳遞什黑。

var x = 10;
var y = 'abc';

var a = x;
var b = y;

console.log(x, y, a, b) // 10, 'abc', 10, 'abc'

ax都包含10崎淳,by都包含'abc'堪夭,并且它們是完全獨立的拷貝愕把,互不干涉。如果我們將a的值改變森爽,x不會受到影響恨豁。

var x = 10;
var y = 'abc';
var a = x;
var b = y;
a = 5;
b = 'def';
console.log(x, y, a, b); // 10, 'abc', 5, 'def'

對象

如果一個變量綁定到一個非基本數(shù)據(jù)類型(Array, Function, Object),那么它只記錄了一個內(nèi)存地址爬迟,該地址存放了具體的數(shù)據(jù)橘蜜。注意之前提到指向基本數(shù)據(jù)類型的變量相當(dāng)于包含了數(shù)據(jù),而現(xiàn)在指向非基本數(shù)據(jù)類型的變量本身是不包含數(shù)據(jù)的。

對象在內(nèi)存中被創(chuàng)建计福,當(dāng)我們聲明arr = []跌捆,我們在內(nèi)存中創(chuàng)建了一個數(shù)組。arr記錄的是該內(nèi)存的地址象颖。

var arr = []; // (a)
arr.push(1); // (b)

當(dāng)執(zhí)行完(a)之后佩厚,內(nèi)存中創(chuàng)建了一個空的數(shù)組對象,其內(nèi)存地址為#001说订,arr指向該地址抄瓦。

變量 地址 對象
arr #001 []

當(dāng)執(zhí)行完(b)之后,數(shù)組對象中多了一個元素陶冷,但是數(shù)組的地址依然沒有變钙姊,arr也沒有變。

變量 地址 對象
arr #001 [1]

引用傳遞

對象是通過引用傳遞埂伦,而不是值傳遞煞额。也就是說,變量賦值只會將地址傳遞過去沾谜。

var reference = [1];
var refCopy = reference;
變量 地址 對象
reference #001 [1]
refCopy #001

referencerefCopy指向同一個數(shù)組立镶。 如果我們更新referencerefCopy也會受到影響类早。

reference.push(2);
console.log(reference, refCopy); // [1, 2], [1, 2]
變量 地址 對象
reference #001 [1, 2]
refCopy #001

引用重新賦值

如果我們將一個已經(jīng)賦值的變量重新賦值媚媒,那么它將包含新的數(shù)據(jù)或則引用地址。

var obj = { first: 'fundebug.com'};
obj = { second: 'fundebug.cn'};

obj從指向第一個對象變?yōu)橹赶虻诙€對象涩僻。

變量 地址 對象
obj #001 {first: 'fundebug.com'}
#002 {second: 'fundebug.cn'}

如果一個對象沒有被任何變量指向缭召,就如第一個對象(地址為#001),JavaScript引擎的垃圾回收機制會將該對象銷毀并釋放內(nèi)存逆日。

== 和 ===

對于引用類型的變量嵌巷,=====只會判斷引用的地址是否相同,而不會判斷對象具體里屬性以及值是否相同室抽。因此搪哪,如果兩個變量指向相同的對象,則返回true坪圾。

var arrRef = ['Hi!'];
var arrRef2 = arrRef;

console.log(arrRef === arrRef2); // true

如果是不同的對象晓折,及時包含相同的屬性和值,也會返回false兽泄。

var arr1 = ["Hi!"];
var arr2 = ["Hi!"];

console.log(arr1 === arr2); // false

如果想判斷兩個不同的對象是否真的相同漓概,一個簡單的方法就是將它們轉(zhuǎn)換為字符串然后判斷。

var arr1str = JSON.stringify(arr1);
var arr2str = JSON.stringify(arr2);

console.log(arr1str === arr2str); // true

另一個方法就是遞歸地判斷每一個屬性的值病梢,直到基本類型位置胃珍,然后判斷是否相同。

函數(shù)參數(shù)

當(dāng)我們將基本類型數(shù)據(jù)傳入函數(shù),函數(shù)會將這些數(shù)據(jù)拷貝賦值給函數(shù)的參數(shù)變量觅彰。

var hundred = 100;
var two = 2;
function multiply(x, y) {
    return x * y;
}
var twoHundred = multiply(hundred, two);

hundred的值拷貝給變量x吩蔑,two的值拷貝給變量y

純函數(shù)

對于一個函數(shù)填抬,給定一個輸入哥纫,返回一個唯一的輸出。除此之外痴奏,不會對外部環(huán)境產(chǎn)生任何附帶影響蛀骇。我們機會稱該函數(shù)為純函數(shù)。所有函數(shù)內(nèi)部定義的變量在函數(shù)返回之后都被垃圾回收掉读拆。

但是擅憔,如果函數(shù)的輸入是對象(Array, Function, Object),那么傳入的是一個引用檐晕。對該變量的操作將會影響到原本的對象暑诸。這樣的編程手法將產(chǎn)生附帶影響,是的代碼的邏輯復(fù)雜和可讀性變低辟灰。

因此个榕,很多數(shù)組函數(shù),比如Array.mapArray.filter是以純函數(shù)的形式實現(xiàn)芥喇。雖然它們的參數(shù)是一個數(shù)組變量西采,但是通過深度拷貝并賦值給一個新的變量,然后在新的數(shù)組上操作继控,來防止原始數(shù)組被更改械馆。

我們來看一個例子:

function changeAgeImpure(person) {
    person.age = 25;
    return person;
}
var alex = {
    name: 'Alex',
    age: 30
};
var changedAlex = changeAgeImpure(alex);
console.log(alex); // { name: 'Alex', age: 25 }
console.log(changedAlex); // { name: 'Alex', age: 25 }

在非純函數(shù)changeAgeImpure中,將對象personage更新并返回武通。原始的alex對象也被影響霹崎,age更新為25。

讓我們來看如何實現(xiàn)一個純函數(shù):

function changeAgePure(person) {
    var newPersonObj = JSON.parse(JSON.stringify(person));
    newPersonObj.age = 25;
    return newPersonObj;
}
var alex = {
    name: 'Alex',
    age: 30
};
var alexChanged = changeAgePure(alex);
console.log(alex); // { name: 'Alex', age: 30 }
console.log(alexChanged); // { name: 'Alex', age: 25 }

我們通過JSON.sringify將對象變?yōu)橐粋€字符串冶忱,然后再通過JSON.parse將字符串變回對象尾菇。通過該操作會生成一個新的對象。

一道簡單的面試題

值傳遞和引用傳遞經(jīng)常在面試中被問到囚枪,來嘗試回答一下如下代碼如何輸出:

function changeAgeAndReference(person) {
    person.age = 25;
    person = {
        name: 'John',
        age: 50
    };
    
    return person;
}
var personObj1 = {
    name: 'Alex',
    age: 30
};
var personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); // -> ?
console.log(personObj2); // -> ?

關(guān)于Fundebug

Fundebug專注于JavaScript派诬、微信小程序、微信小游戲眶拉、支付寶小程序千埃、React Native憔儿、Node.js和Java實時BUG監(jiān)控忆植。 自從2016年雙十一正式上線,F(xiàn)undebug累計處理了7億+錯誤事件,得到了Google朝刊、360耀里、金山軟件、百姓網(wǎng)等眾多知名用戶的認(rèn)可拾氓。歡迎免費試用冯挎!

版權(quán)聲明:

轉(zhuǎn)載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/08/09/explain_value_reference_in_js/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市咙鞍,隨后出現(xiàn)的幾起案子房官,更是在濱河造成了極大的恐慌,老刑警劉巖续滋,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翰守,死亡現(xiàn)場離奇詭異,居然都是意外死亡疲酌,警方通過查閱死者的電腦和手機蜡峰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗恳,“玉大人湿颅,你說我怎么就攤上這事≈嘟耄” “怎么了油航?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怀浆。 經(jīng)常有香客問我劝堪,道長,這世上最難降的妖魔是什么揉稚? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任秒啦,我火速辦了婚禮,結(jié)果婚禮上搀玖,老公的妹妹穿的比我還像新娘余境。我一直安慰自己,他們只是感情好灌诅,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布芳来。 她就那樣靜靜地躺著,像睡著了一般猜拾。 火紅的嫁衣襯著肌膚如雪即舌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天挎袜,我揣著相機與錄音顽聂,去河邊找鬼肥惭。 笑死,一個胖子當(dāng)著我的面吹牛紊搪,可吹牛的內(nèi)容都是我干的蜜葱。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼耀石,長吁一口氣:“原來是場噩夢啊……” “哼牵囤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起滞伟,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤揭鳞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后梆奈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汹桦,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年鉴裹,在試婚紗的時候發(fā)現(xiàn)自己被綠了舞骆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡径荔,死狀恐怖督禽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情总处,我是刑警寧澤狈惫,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站鹦马,受9級特大地震影響胧谈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荸频,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一菱肖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧旭从,春花似錦稳强、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鸽素,卻和暖如春褒繁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背馍忽。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工棒坏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留燕差,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓俊抵,卻偏偏與公主長得像谁不,于是被迫代替她去往敵國和親坐梯。 傳聞我的和親對象是個殘疾皇子徽诲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,132評論 0 13
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔吵血,今天18年5月份再次想寫文章谎替,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 2,739評論 2 9
  • 2006-11-06 22:31 生活已如一杯白開水钱贯,越來越來不是滋味。我住的城市最近總愛刮風(fēng)侦另,風(fēng)帶著沙子秩命,也帶著...
    千尋滿意閱讀 186評論 0 0
  • 一張相思網(wǎng),攜帶千千結(jié)褒傅。 漂泊異鄉(xiāng)人弃锐,千結(jié)亦難解。 難解是千結(jié)殿托?不霹菊,不,不支竹! 鄉(xiāng)情最撩人旋廷,游心最難撫。
    王慕林閱讀 1,486評論 27 43
  • 《彭博新聞周刊》最近刊登了一個非常有意思的新聞礼搁,大意是雖然自2008年以來一直深受經(jīng)濟衰退影響饶碘,失業(yè)率高達27.2...
    叆如閱讀 526評論 0 35