1. 程式人生 > >javascript中所有函式引數都是按值傳遞

javascript中所有函式引數都是按值傳遞

在看《JavaScript高階程式設計》(第三版)的時候,傳遞引數這一節,裡面提到

ECMAScript中所有函式的引數都是按值傳遞的

它自己的解釋是,

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

我們先明白幾個概念,之後再討論。

資料型別

基本資料型別,有6種,Undefined、Null、Boolean、Number、String、Symbol

引用型別,Object、Array、Date、RegExg、Function等

記憶體空間

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

定義的以上幾個變數,在記憶體中,所佔用的空間如圖示意:

記憶體空間示意圖

基礎資料型別值,在棧中儲存實際的值。引用資料型別值,在棧中儲存引用地址值,在堆中儲存實際的值。

賦值拷貝/複製

基礎資料型別,賦值拷貝,拷貝實際值


var a = 1

var b = a

b = 2

console.log(a) // 1

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所有函式引數傳遞

在看《JavaScript高階程式設計》(第三版)的時候,傳遞引數這一節,裡面提到 ECMAScript中所有函式的引數都是按值傳遞的 它自己的解釋是, 把函式外部的值複製給函式內部的引數,就和把值從一個變數複製到另一個變數一樣。 基本型別值的傳遞如同基本型別變數的複製一樣, 而引用型別值的傳遞,則如同

js函式引數傳遞的,不是引用傳遞

今天看到高程關於傳遞引數這一張的時候,說到,引數不管是基本型別還是引用型別的傳遞都是按值傳遞,但是 demo:   function setName(obj){ obj.name=“Nicholas”; obj=new Object(); obj.name=“Greg”;

四、1、函式引數傳遞還是引用傳遞

參考連結:https://www.zhihu.com/question/27114726 http://bosn.me/js/js-call-by-sharing/     基本型別在函式引數中肯定是

JS函式引數傳遞還是引用傳遞

《JavaScript高階程式設計(第3版)》中P70頁關於傳遞引數一上來就各種強調開發人員會錯誤的認為引數是按引用傳遞,前後看了幾遍,甚是迷惑,被幾個概念繞得暈乎,說的是玄之又玄,於是花了一下午準備把這個點的所有概念理清。一、兩種不同資料型別的值基本型別值,指簡單的資料段,

C++函式引數的物件傳遞問題

c++中函式的引數是值傳遞的時候,就會容易出現問題。比如int foo(Object a){}; Object a;foo(a);a作為引數傳入,進去呼叫函式,產生一個臨時的,區域性的,在棧中的物件a',a'是a的位拷貝。這樣子,當函式結束是,臨時物件a'的作用域結束,會呼叫

解惑:Java的方法引數總是傳遞

程式設計語言中往往分成按值呼叫和按引用呼叫。按值呼叫(call by value)表示方法接收的是呼叫者提供的值。而按引用呼叫(call by reference)表示方法接收的是呼叫者提供的變數地址。一個方法可以修改傳遞引用所對應的變數值,而不能修改傳遞值呼叫所對應的變數值。 ​

JAVA 方法的引數傳遞還是引用傳遞

在思考這個問題之前首先要明白JAVA一個類中的資料成員有多少種:                    JAVA一個類中資料成員只有兩種,分別是:基本資料型別和物件。基本資料型別就不用多說了,只有8種;其他的都是物件,JAVA class位元組碼檔案在記憶體中是一個靜態物件、

Javascript函式引數傳遞

網站資訊 文章數:581 篇 評論數:2006 條 標籤數:1184 個 頁面數:7 個 友鏈數:20 條 使用者數:13092 位 共執行:2562 天 建站日期:2011.11.17 最近更新:2018.11.17 註冊登入 據說本站已備案,不管你信不信,反正我信了. ^_^

JS函式引數傳遞到底是傳遞還是引用傳遞

首先我們知道JS中的資料型別大致可以分為簡單資料型別和複雜資料型別; 當我們宣告一個變數並給它賦值時,可以賦給其簡單值和複雜值(以下堆記憶體和棧記憶體的地址表示均隨意取的,只是為了區分,不代表真實的記憶體地址); 針對簡單資料型別: 例1 var simpleData1 = 18 v

如何理解JavaScript引數傳遞

開始之前先說一下 ES 中的兩種資料型別的值:基本型別值和引用型別值。 基本資料型別:Undefined、Null、Boolean、Number、String。 引用資料型別的值是儲存在記憶體中的物件。與其他語言不同,JavaScript 不允許直接訪問記憶體中的位置,也就是說不能直

js的函式傳遞引數(例項講解)

js的函式傳參的方式是按值傳遞,正常情況下,改變函式引數的值,並不會對函式外部的變數造成影響。例如: ? 1 2 3 4 5 6 'use strict'; var list = [1, 2,

javascriptbind()函式實現和應用以及多次bind的結果和引數位置的思考

改變物件方法裡this的值var ob = { name: 'joe', getName: function () { alert(this.name); } }; // 改變getName方法裡原本的this物件為新物件{name: 'haha'} var app = ob.getName.bi

python3.x宣告函式時的預設引數問題

宣告一個引數具有預設值的函式形式如下: def <函式名> (引數=預設值):         <函式語句> eg: def hello(name='python'):          print('你好,我是: %s' %name) h

js 函式引數傳遞的理解

例子選自《javas高階程式設計》1.基本型別按值傳遞function addTen(num) { num += 10; return num; } var count = 20; var result = addTen(count); alert(count); //20,

python傳遞引數還是引用傳遞引數

在學習python函式的時候,遇到了一個非常有趣的問題: 在函式中的引數是如何傳遞的:是傳值?還是傳引用?當然,結果我們是知道的,肯定是傳引用的。 現在,我們來測一下我們的結論: ===== 修改li

關於C++裡面的函式傳遞引用傳遞的區別

在c++中,一般有兩種傳遞方式:一種是引用按值傳遞,另一種是按引用傳值, 其我們經常在java中寫一些方法呼叫,當傳遞基本型別時,都是按指傳遞,在 傳遞物件時,都是按引用型別傳遞。 那麼這兩種

C++陣列作為函式引數或返回

C++中陣列作為函式引數或者返回值 概述 在程式設計任務中,經常會遇到將陣列作為函式引數或者返回值,比如在前一篇的計數排序任務中,需要額外的空間來儲存排序後的元素,並且將該陣列返回給主函式。本文會介紹幾種可行的方案,僅供參考。 陣

JavaScript引數傳遞

開發十年,就只剩下這套架構體系了! >>>   

javascript構造函數的返回問題和new對象的過程

key 調用 size def var define 過程 創建對象 article 首先明白一點:javascript中構造函數是不須要有返回值的,這一點跟java非常類似。能夠覺得構造函數和普通函數的最大區別就是:構造函數中沒有ret

遍歷一個對象所有屬性所對應的

對象 屬性 值和遍歷 數組中的每一個元素的方法很類似註意:在遍歷數組時 其中的i對應著數組的下標。遍歷一個對象中所有屬性所對應的值