javascript中全部函數參數都是按值傳遞

在看《JavaScript高級程序設計》(第三版)的時候,傳遞參數這一節,裏面提到javascript

ECMAScript中全部函數的參數都是按值傳遞的html

它本身的解釋是,java

把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。
基本類型值的傳遞如同基本類型變量的複製同樣,
而引用類型值的傳遞,則如同引用類型變量的複製同樣。git

咱們先明白幾個概念,以後再討論。github

數據類型

基本數據類型,有6種,Undefined、Null、Boolean、Number、String、Symbol函數

引用類型,Object、Array、Date、RegExg、Function等設計

數據類型介紹,能夠參考JavaScript數據類型的很是6+1code

內存空間

var a = 2
var b = 'abc'
var c = true
var d = {value : 1}
var e = [1, 2, 3]

定義的以上幾個變量,在內存中,所佔用的空間如圖示意:htm

內存空間示意圖

基礎數據類型值,在棧中存儲實際的值。引用數據類型值,在棧中存儲引用地址值,在堆中存儲實際的值。對象

賦值拷貝/複製

基礎數據類型,賦值拷貝,拷貝實際值

var a = 1

var b = a

b = 2

console.log(a) // 1

引用類型,賦值拷貝,拷貝引用地址,淺拷貝。能夠參考javascript中的淺拷貝ShallowCopy與深拷貝DeepCopy

var a = {value : 1}

var b = a

b.value = 2

console.log(a.value) // 2

舉例分析

明白了以上幾個概念,咱們再來講說,把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。也就是一個賦值複製過程。咱們舉幾個例子分析下。

1. 傳遞基礎類型,函數中不修改參數類型

var a = 1

function func(o) {

    o = 2

    console.log(o)

}

func(a) // 2

console.log(a) // 1

這裏的func函數,傳遞了一個參數o,而參數其實是函數的局部變量。那麼,咱們就能夠修改函數

var a = 1

function func() {

    var o = a // 函數內部的參數變量,賦值函數外部的值

    o = 2 // 修改內部變量的值

    console.log(o)

}

func(a) // 2

console.log(a) // 1

能夠獲得相同的結果。他們在內存中的變化,如圖示意:
傳遞基礎類型,函數中不修改類型

從以上圖中,咱們能清楚的看出,變量a一直等於1,而變量o,因爲賦值以後,複製了a的實際值,在內存中開闢了空間,存儲在棧中。再執行func函數,修改變量o的值,只會影響其自身。

2. 傳遞基礎類型,函數中修改類型

var a = 1

function func(o) {

    o = {value : 1}

    console.log(o)

}
func(a) // {value: 1}

console.log(a) // 1

同理,咱們也能夠修改這裏的函數

var a = 1

function func() {

    var  o = a // 函數內部的參數變量,賦值函數外部的值

    o = {value : 1} // 修改內部變量的值

    console.log(o)  // {value: 1}

}
func() // {value: 1}

console.log(a) // 1

內存中的變化示意圖:
傳遞基礎類型,函數中修改類型

從以上圖中,咱們能清楚的看出,變量a一直等於1,而變量o,因爲內部參數賦值以後,複製了a的實際值,在內存中開闢了空間,存儲在棧中。再執行func函數,修改變量o的值,只會影響其自身。

3. 傳遞引用類型,函數中不修改類型

var a = { value : 1 }

function func(o) {

    o.value = 2

    console.log(o)

}

func(a) // { value : 2}

console.log(a) // {value : 2}

同理,咱們也能夠修改這裏的函數

var a = { value : 1 }

function func() {

    var  o = a // 函數內部的參數變量,賦值函數外部的值

    o.value = 2 // 修改內部變量的值

    console.log(o)  // {value: 2}

}
func() // {value: 2}

console.log(a) // {value: 2}

內存中的變化示意圖:
傳遞引用類型,函數中不修改類型

從以上圖中,咱們能清楚的看出,因爲變量a是引用類型,經過函數內部參數的賦值複製,傳遞了引用地址值,那麼變量ao會指向同一個內存對象。再執行func函數,修改變量o在堆內存中的值,並無修改在棧中的引用地址的值。這樣,因爲變量o和變量a使用的是同一個引用地址,也就是同一個堆內存中的值,那麼變量a的值,也就會隨着變量o的變化而變化了。

4. 傳遞引用類型,函數中修改類型

var a = {value : 1 }

function func(o) {

    o = 2

    console.log(o)

}

func(a) // 2

console.log(a) // { value : 1}

接下來,咱們也能夠修改這裏的函數

var a = { value : 1 }

function func() {

    var  o = a // 函數內部的參數變量,賦值函數外部的值

    o = 2 // 修改內部變量的值

    console.log(o)  // 2

}
func() // 2

console.log(a) // {value: 1}

內存中的變化示意圖:
傳遞引用類型,函數中修改類型

因爲變量a是引用類型,經過函數內部參數的賦值複製,傳遞了引用地址值,那麼變量ao會指向同一個內存對象。再執行func函數時,改變了變量o的數據類型,變成了基礎數據類型,也就切斷了引用。這樣,變量ao就沒有關係了。

總結

JavaScript中全部函數參數都是按值傳遞的。基本類型值,傳遞的是實際值,引用類型,傳遞的是引用地址值。

參考

JavaScript深刻之參數按值傳遞

內存空間詳解

相關文章
相關標籤/搜索