1. 程式人生 > >JS 的引用賦值與傳值賦值

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 )