JavaScript的賦值是引用or復制,及參數傳遞


先來看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,如果回答得正確,就沒必要看下去。If not,就跟我一起來學習下好啦~

(一)基本類型

由於學js沒多久,對賦值究竟是引用還是復制不是很清楚(如果是引用,那一個值改變會影響另一個,如果是復制,那各玩各的,互不影響),遇到這類問題往往就很迷糊。花了半天時間參閱了一些資料,整理如下。

首先,JavaScript的基本類型有boolean, string, number,還有undefined和null,啊你肯定會說干嘛又扯最無聊的any book的語法第一章內容,了解這個又怎么樣,還真的有用呢。首先得明白的是,只有字面量的boolean,string和number,以及undefined + null(exact undefined null,區分大小寫)才是屬於基本類型的,new出來的不算。

即:

alert(typeof false);//"boolean"
var b = new Boolean(false);
alert(typeof b);//"object"

同樣,new String('aaa')這種都不是基本類型,直接的a = 'aaa',a是基本類型,這就是:字面量的才是基本類型。

另一方面,Object,Function,Array其實都是構造函數,因為可以直接new Object()等,所以它們都是函數,so (Object instanceof Function === true) &&(Function instanceof Object===true).

要注意的是,基本類型沒有屬性和方法,但它們可以調用對應基本包裝類型的方法,可以來看下面的例子:

var a = 'ot';
a.age = 18;//hahahahaha, yeah, forever 18
alert(a.age);//undefined
a.length = 160;
alert(a.length);//2

第二步的a.age = 18其實在實現的時候分成三步:

var s1 = new String('ot');
s1.age = 18;
s1 = null;

即基本類型每次調用類型或方法都會創建新對象,隨后便銷毀。

同樣,在alert(a.age)的時候,分為下列步驟:

var s2 = new String('ot');
alert(s2.age);
s2 = null;

因為沒有對s2定義age方法,所以輸出為undefined。在alert(a.length)的時候,由於s3 = new String('ot'),String有length方法,所以,會輸出結果,當然,上一步的賦值操作的對象也一定已經被銷毀了。

(二)引用or Copy

Clear about基本類型后,要了解的是,基本類型變量存在棧內部,每賦值一次就創建一個新的copy,然后play with itself. 而除了基本類型之外的引用類型,則存在堆內存中,只能引用。可以來看下面的例子:

var ot = new Object();//創建一個對象,把地址賦值給ot,即ot指向這個地址
var op = ot;//把ot的值賦給op,所以op也是指向那個對象
op.age = 18;
alert(ot.age);//18

op = new String('sunshine');//把新創建對象的地址賦給op, ot當然不變
alert(ot.length);//undefined

看了注釋部分,相信已經能理解了。

(三)參數傳遞

Javascript的參數傳遞為值傳遞,我們來看下面的例子:

function setAge(i)
{
    alert(i);//24
    i = 18;
    alert(i);//18
};

var ot = 24;
setAge(ot);

alert(ot);//24

把ot的值24傳遞進去,賦值給i,於是第一個alert的是24,然后i重新賦值,於是alert出來的是18,但外層的ot不受影響,因為傳遞值,也就是復制了份內容給i而已。

那傳遞的值為引用類型時會怎么樣呢?先看例子:

function setName(obj)
{
    obj.name = 'ot';
};

var obj2 = new Object();
setName(obj2);
alert(obj2.name);//ot

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

(四)回到面試題

我們現在再來看前面的面試題:

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);

首先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仍然改變的)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM