js函數傳參是按值傳遞還是按引用傳遞?


閑扯一蛋

最近各大互聯網巨頭的校招相繼啟動,看得我們這些准大四的碼農想入非非。雖然早已經找到東家,但是畢竟阿里網易的名字對我們這些屁事不懂的應屆生而言,還是極具吸引力的,所以這幾天內心還是非常掙扎的,考慮再三,還是決定安心待在現在的公司,忍不住想誇自己忠如狗了!
也是在掙扎的那幾天,去網上看了些前端筆試面試題,不由產生蛋蛋的憂傷。雖然已經實習了快5個月,做一些基礎題還是會有很多問題,只能說基礎不扎實呀。回想這實習的5個月,業務做得不少,熟練度直線提升,然而歸納總結寥寥無幾。這讓我又想起了,之前看到關於為什么寫技術博客的原因。突然深深地體會到,不去花時間總結,平時業務上用到的零散知識點就很難形成體系,另外,僅僅只是在業務上碰到問題,查找解決方案,然后把問題解決了就帶過,這樣的學習方式是非常危險的。這是實習以來深深的痛點!
按照我現在的認識,現階段做業務是必須的,遇到問題,查找解決方案,確定知識點,業余時間深入去學習該知識點,形成自己的理解。另外時不時去回顧下基礎的書籍,從而形成自己的知識體系。所以,這周開始重新翻一遍js高程的基礎。

基本類型、引用類型

閑扯完了,開始寫今天要總結的基礎知識。

基本類型: undefined、Null、Boolean、Number、String五種 (簡單的數據段);
引用類型: object (由多個值構成)。

兩種類型在使用上的區別:

復制變量
這塊好理解,看一個例子的對比就秒懂:

// 基本類型
var num1 = 5;
var num2 = num1;
num2 = 10;
console.log(num1 + ' | ' + num2); // 5 | 10

// 引用類型
var obj1 = new Object();
obj1.num = 5;
var obj2 = obj1;
obj2.num = 10;
console.log(obj1.num + ' | ' + obj2.num); // 10 | 10

一句話,引用類型復制的是指針的指向。
傳遞參數
剛開始看書上,說的是“按值傳遞”。然后拋出一個例子:

function addTen(num) {
num += 10;
return num;
}

var count = 20;
var result = addTen(count);
console.log(count + ' | ' + result); // 20 | 30

看完這個例子,秒懂按值傳遞。緊接着又來一段代碼:

function setName(obj) {
obj.name = 'aaa';
return obj;
}

var person = new Object();
person.name = 'bbb';
var newPerson = setName(person);
console.log(person.name + ' | ' + newPerson.name); // aaa | aaa

看完這個例子,我就懵逼了。這段代碼不是解釋成按引用傳遞更合理嗎?
然后又給了一個證明就算參數是引用類型也是按值傳遞的例子:

function setName(obj) {
obj.name = 'aaa';
var obj = new Object(); // 如果是按引用傳遞的,此處傳參進來obj應該被重新引用新的內存單元
obj.name = 'ccc';
return obj;
}

var person = new Object();
person.name = 'bbb';
var newPerson = setName(person);
console.log(person.name + ' | ' + newPerson.name); // aaa | ccc

從結果看,並沒有顯示兩個'ccc'。這里是函數內部重寫了obj,重寫的obj是一個局部對象。當函數執行完后,立即被銷毀。
到這里,js高程解釋完了按值傳遞和按引用傳遞。然而對於我這樣智商略平的同學而言,還是一臉懵逼。於是去網上深入地了解了下。

引用值:對象變量它里面的值是這個對象在堆內存中的內存地址。因此如果按引用傳遞,它傳遞的值也就是這個內存地址。那么var obj = new Object();會重新給obj分配一個地址,比如是0x321了,那么它就不在指向有name = 'aaa';屬性的內存單元了。相當於把實參obj和形參obj的地址都改了,那么最終就是輸出兩個ccc了。

最后看個例子,弄懂了也就差不多理解了。

# 作者信息
var a = {
num:'1'
};

var b = {
num:'2'
};

function change(obj){
obj.num = '3';
obj = b;
return obj.num;
}

var result = change(a);
console.log(result + ' | ' + a.num); // 2 | 3 

走一遍思路:
首先把a的值傳到change函數內,obj.num = '3';a.name被修改為3;
a的地址被換成b的地址;
返回此時的a中a.num

按共享傳遞
在網上還看到一種叫 按共享傳遞 的說法,而且特別好理解。
大致概念是這樣的:調用函數傳參時,函數接受對象實參引用的副本(既不是按值傳遞的對象副本,也不是按引用傳遞的隱式引用)。 它和按引用傳遞的不同在於:在共享傳遞中對函數形參的賦值,不會影響實參的值。

可以回過頭去看之前的例子,每個都符合用共享傳遞的概念去進行參數傳遞。關鍵是特別好理解,說的通俗點就是 先復制參數,然后把復制的這個放函數里面去折騰。
例子就不展開了,看官可以自己套幾個demo。

對基本類型和引用類型的討論主要在 函數參數的傳遞方式這塊,希望對正在夯實js基礎的你有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM