不少人,包括我,受書本知識消化不完全的影響,認爲 JS 中參數有兩種傳遞方式:數字、字符串等按值傳遞;數組、對象等按地址(引用)傳遞。對此種觀點,咱們要謹慎。javascript
var v1 = []
var v2 = {};
var v3 = {};
function foo(v1, v2, v3)
{
v1 = [1];
v2 = [2];
v3 = {a:3}
}
foo(v1, v2, v3);
alert(v1); // 空白
alert(v2); // [object Object]
alert(v3.a); // undefined
因而可知:v一、v二、v3 都沒有被改變,v1 仍然是零個元素的數組,v二、v3 仍然是空白的對象。java
可是,數組、對象等按值傳遞,是指變量地址的值。c++
數組、對象等的按值傳遞與數字、字符串仍是有所不一樣的。數字、字符串是把值直接複製進去了,而數組、對象是把變量地址複製進去的。數組
前面咱們讓 v一、v二、v3 做爲參數進入函數後,就有了地址副本,這些地址副本的指向和外面的 v一、v二、v3 的地址指向是相同的。但咱們爲 v一、v二、v3 賦了值,也就是說咱們把地址副本的指向改變了,指向了新的數組和對象。這樣內部的 v一、v二、v3 和外部的 v一、v二、v3 就徹底斷了。函數
若是咱們不賦新值,而是直接操做它,那麼,它操做到的,仍然是和外面的 v一、v二、v3 指向的同一塊數組或對象。this
var v1 = []
var v2 = {};
var v3 = {a:0};
function foo(v1, v2, v3)
{
v1.push(1);
v2.a = 2;
v3.a = 3;
}
foo(v1, v2, v3);
alert(v1); // 1
alert(v2.a); // 2
alert(v3.a); // 3
轉自:http://www.cftea.com/c/2010/07/TKE282SFVCKL2RLS.aspspa
這種傳地址的方式相似傳引用,只不過c++引用在建立時就規定好了,不能更改,這裏的地址相似引用,但能夠更改。設計
下面的例子:指針
var c1 = {v:1};
var c2 = c1;
c2.v = 11;
c2 = {v:2};
alert(c1.v); // 顯示 11
alert(c2.v); // 顯示 2
其實這個例子好理解, c2 賦新對象,c1 仍舊是老對象。code
這個彷佛有點小兒科。
function c()
{
var obj = {v:1};
obj.func = function()
{
obj.v = 2;
};
return obj;
}
var c1 = c();
c1.func();
alert(c1.v); // 顯示 2
var c2 = new c();
c2.func();
alert(c2.v); // 顯示 2
因爲 c 中使用了 return,因此 new 不 new 都同樣,這裏是直接操做的 obj 的屬性,沒有賦新對象,因此顯示更改後的值 2。
function c()
{
var obj = {v:1};
obj.func = function()
{
obj = {v:2};
};
return obj;
}
var c1 = c();
c1.func();
alert(c1.v); // 顯示 1
var c2 = new c();
c2.func();
alert(c2.v); // 顯示 1
這裏顯示 1,是因爲爲 obj 賦了新對象,而 return 後造成的變量(c一、c2)與 obj 是兩個變量,因此 return 後造成的變量仍舊是老對象。
function c()
{
this.obj = {v:1};
this.func = function()
{
this.obj = {v:2};
};
}
/*
var c1 = c();
c1.func();
alert(c1.obj.v);
*/
var c2 = new c();
c2.func();
alert(c2.obj.v); // 顯示 2
這裏顯示 2,是因爲使用了 this。
轉自:http://www.cftea.com/c/2010/09/5HU6LYB83MXXRL96.asp
在傳統的觀念裏,都認爲JavaScript函數傳遞的是引用傳遞(也稱之爲指針傳遞),也有人認爲是值傳遞和引用傳遞都具有。那麼JS的參數傳遞究竟是怎麼回事呢?事實上如下的演示也徹底能夠用於Java
首先來一個比較簡單的,基本類型的傳遞:
function add(num){
num+=10;
return num;
}
num=10;
alert(add(num));
aelrt(num);
//輸出20,10
對於這裏的輸出20,10,按照JS的官方解釋就是在基本類型參數傳遞的時候,作了一件複製棧幀的拷貝動做,這樣外部聲明的變量num和函數參數的num,擁有徹底相同的值,但擁有徹底不一樣的參數地址,二者誰都不認識誰,在函數調用返回的時候彈出函數參數num棧幀。因此改變函數參數num,對原有的外部變量沒有一點影響。
再來看一個較複雜的,對象引用類型的傳遞:
function setName(obj){
obj.name="ted";
}
var obj=new Object();
setName(obj);
alert(obj.name);
//輸出ted
以上代碼的運行的實質是:建立了一個object對象,將其引用賦給obj(在C裏面就直接是一個內存地址的賦值),而後在傳遞函數參數的時候,作了一件與前一個方法相同的事情,複製了一個棧幀給函數參數的obj,二者擁有相同的值(不妨將其理解爲object對象的地址),然後在setName作改變的時候,事實上是改變了object對象自身的值(在JAVA裏稱之爲可變類),在改變完成以後一樣也要彈出函數參數obj對應的棧幀。
因此對應的輸出是改變後object對象的值
那麼可能有的朋友可能會問,這樣也能夠理解爲一個引用傳遞(指針傳遞)呀?不,這裏嚴格的說,在和JAVA相似的語言中,已經沒有了指針,在JAVA裏將上述過程稱之爲一個從符號引用到直接引用的解析過程。在C裏面,指針就是一個具備固定長度的類型(在大多數的C編譯器裏是2個字節),但在JAVA相似的語言裏,引用也有本身的屬性和方法,只是你不能直接去訪問和控制它,因此它從某種意義上也是一種對象,這種機制也很大程度的避免了內存泄露,術語稱之爲內存結構化訪問機制。
爲了證實上述觀點,稍微改造下上述例子:
function setName(obj){
obj.name="ted";
obj=new Object();
obj.name="marry";
}
var obj=new Object();
setName(obj);
alert(obj.name);
//輸出ted
這個例子與上一個例子的惟一不一樣是這裏將一個新的對象賦給了函數參數obj,這樣函數參數obj和原有的引用obj參數,有着徹底不一樣的值和內存地址。
值的一提的是,在Python中就沒有這樣的爭論,由於Python裏面一切都是對象,只是對象能夠按照存儲類型(容器類型仍是標量模型) 、更新類型(是否可變)、訪問模型(直接訪問、序列訪問、映射訪問)來劃分,訪問模型是最多被討論的,也是最清晰的區分方式。因此毫無疑問,在Python裏面,函數傳遞方式只有一種---引用對象傳遞
-------------
JavaScript函數參數,傳值仍是傳址?
首先,十萬以及萬分確定的說一句, JavaScript 函數傳遞參數時,是值傳遞。雖然您可能不信,由於 ECMAScript 變量可能包含兩種不一樣數據類型的值:基本數據類型,和引用數據類型。難道引用數據類型傳遞的時候難道也是值傳遞嗎?答,沒錯。
引用類型的值是什麼東西?
當一個變量向另外一個變量複製引用類型的值時,會將存儲在棧中的值(棧中存放的值是對應堆中的引用地址)複製一份到爲新變量分配的空間中。
不一樣的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。複製操做結束後,兩個變量實際上引用同一個對象。
var user = new Object();
var admin = user;
admin.name = "xiaoxiaozi";
alert(user.name); //返回 xiaoxiaozi
該過程實際上是這樣的(引用型變量的複製):
因此說,引用類型的值其實是對其引用對象的一個指針。
函數參數的傳遞
基本類型咱們不作討論,那玩意除了值還真沒別的。我們繼續來講引用類型。請看下面示例:
function setName(obj){
obj.name = "xiaoxiaozi";
}
var person = new Object();
setName(person);
alert(person.name); // 返回 xiaoxiaozi
在向參數傳遞引用類型值時,會把這個值在內存中的地址複製給一個局部變量,所以這個局部變量的變化會反映在函數的外部。
ECMAScript 中,全部函數的參數都是按值來傳遞的。基本類型值的傳遞和基本類型變量複製一致(採用在棧內新建值),引用類型值的傳遞和引用類型變量的複製一致(棧內存放的是指針,指向堆中同一對象)
所以在調用函數setName()時,person 被複制給了 obj ,所以在函數內部 obj 與 person 引用的是同一個對象,或者說是對同一個對象的引用。因此在給 obj 引用對象加上 name 屬性時,person 引用的對象也有了 name 屬性,由於雖然 obj 與 person 不一樣,可是兩者引用的對象是同一個。
可是,千萬不要認爲,在局部做用域中修改的對象會在全局做用域中反映出來就說參數是按引用傳遞的。爲了證實是值傳遞,讓咱們再來看以下例子:
function setName(obj){
obj.name = "xiaoxiaozi";
obj = new Object();
obj.name = "admin";
}
var person = new Object();
setName(person);
alert(person.name); // 結果依舊是 xiaoxiaozi
在調用 setName() 函數初時,obj 與 person 引用的是同一對象,因此首次的 name 屬性賦值會對 person 有所影響。可是當 obj 被從新定義時,其引用的對象已經與 person 不一樣,因此後面設置的 name 屬性,不會對 person 引用的對象有任何影響。
感受上面的這個例子很是好,你們能夠仔細體會一下,我也是看到了這個例子才決定從文中《javascript高級程序設計》摘抄(貌似沒有摘,就是抄)的。
原文連接:JavaScript 傳遞參數是值傳遞?仍是值傳遞啊?