JS 的引用賦值與傳值賦值

這個問題說大不大說小不小,如果你有幸踩了這個坑,一定會找這篇文章,哈哈~

現說一下JS數字的類型:基本類型引用類型

先看下下面兩個栗子:

1
2
3
4
5
6
7
8
9
var a = 30;
var b = a;
a = 20;
console.log( b )   // 30
 
var a = [1,2];
var b = a;
a[0] = 5;
console.log( b )  // [5,2]

簡單的說:

number,string類型都是基本類型,而基本類型存放在棧區,訪問時按值訪問,賦值是按照普通方式賦值;

對象和數組是通過引用來賦值的,所以改變a的同時b也會跟着改變。

解決辦法:

1. var a = [1,2];
var b = a.slice(0);
b[0] = 3;
alert(a) //1,2
 
2. var a = [1,2];
var b = a.concat(0);
 
concat會直接返回新的數組對象

好了下面詳細的說,看了上面秒懂的直接忽略(直接看下面阿里的面試題);

1、基本類型

基本的數據類型有:undefined,boolean,number,string,null。 基本類型存放在棧區,訪問是按值訪問的,就是說你可以操作保存在變量中的實際的值。

當基本類型的數據賦值時,賦得是實際的值,a和b是沒有關聯關係的,b由a複製得到,相互獨立。(字面量的纔是基本類型)

var a=10;

var b=a;

console.log(a+','+b);    // 10,10
a++;
console.log(a+','+b)  // 11,10
 

2、引用類型

引用類型指的是對象。可以擁有屬性和方法,並且我們可以修改其屬性和方法。引用對象存放的方式是:在棧中存放對象變量標示名稱和該對象在堆中的存放地址,在堆中存放數據。

對象使用的是引用賦值。當我們把一個對象賦值給一個新的變量時,賦的其實是該對象的在堆中的地址,而不是堆中的數據。也就是兩個對象指向的是同一個存儲空間,無論哪個對象發生改變,其實都是改變的存儲空間的內容,因此,兩個對象是聯動的。

 

 3、數組是引用類型

我們先來看一個例子:

var [1,2,3];

var a;

[4,5,6];

alert(b); //[1,2,3]

 好像數組是基本類型一樣。。,但是:

var [1,2,3];

var a;

a.pop();

alert(b); //[1,2]

這是怎麼回事?因爲:(知乎解釋)

a = [4,5,6];//改變的是a引用本身,沒有改變數組對象,a和b沒有了關係。
a.pop();//改變的是數組對象,a引用沒有改變。
b = a;//該操作後,b直接指向數組對象,不是b指向a,a再指向數組。
//所以改變a引用並不會對b引用造成影響,改變數組對象可以。

作者:Intopass
鏈接:https://www.zhihu.com/question/26042362/answer/31903017
來源:知乎

這個問題就跟我之前在React todo-list 一篇中提到的問題一樣:

var tasks=this.state.data;
  tasks=tasks.filter(function(i){
     return i.index!=taskId;  
 });

由於filter函數是返回一個新的數組,雖然仍然用tasks去接收,但這時候tasks的指向已經是新數組啦,所以tasks和data已經不在有關係。(concat也是返回新數組)

 而push和splice函數是在原數組上操作,所謂在原數組操作,指的是指向不變,所以tasks和data是相關聯的。

 

4、參數傳遞

js的函數參數傳遞爲值傳遞。

當傳入的是 基本類型的參數時:就是複製了份內容給i而已,i與age之間沒有關係。

function setAge(i)

{
    alert(i);//24
    i = 18;
    alert(i);//18,i的改變不會影響外面的age
};
 
var age = 24;
setAge(age);
alert(age);//24

當傳入的參數爲引用類型時:

function setName(obj)

{
    obj.name = 'haha';
};
 
var obj2 = new Object();
setName(obj2);
alert(obj2.name);    //  haha

這看起來很像是傳遞的是引用,因爲obj.name受到改變了,但其實不是,其實還是值,因爲obj2本身的值就是新對象的地址,所以傳進去的就是這個地址。

 

這是阿里2014年的筆試題: 

var a = 1;

var obj = {
    b: 2
};
var fn = function () {};
fn.c = 3;
 
function test(x, y, z) {
    x = 4;
    y.b = 5;
    z.c = 6;
    return z;
}
test(a, obj, fn);
alert(a + obj.b + fn.c);

答案:12

 首先test傳遞進去的實參中,a是基本類型(,複製了一份值),obj是object(指向地址,你動我也動),fn也當然不是基本類型啦。在執行test的時候,x被賦值爲4(跟a沒關係,各玩各的,a仍然爲1),y的b被賦值爲5,那obj的b也變爲5,z的c變爲6,那fn的c當然也會是6. 所以alert的結果應該是1+5+6 =12. (其實test不返回z也一樣,z仍然改變的)。

var a = 30;var b = a;a = 20;console.log( b )
var a = [1,2];var b = a;a[0] = 5;console.log( b )

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章