面試官想要的 JS 基本類型

面試的時候我們經常會被問答js的數據類型。大部分情況我們會這樣回答包括:

  1. 基本類型(值類型或者原始類型): Number、Boolean、String、NULL、Undefined以及ES6的Symbol;
  2. 引用類型:Object、Array、Function、Date等。

作者曾經也是這樣回答的,并且一直覺得沒有什么問題。那么面試官問你 JS 數據類型時,他想知道什么呢?接著往下看??????

1. 在內存中的位置不同

  • 基本類型: 占用空間固定,保存在棧中
  • 引用類型:占用空間不固定,保存在堆中

棧(stack)為自動分配的內存空間,它由系統自動釋放;使用一級緩存,被調用時通常處于存儲空間中,調用后被立即釋放。
堆(heap)則是動態分配的內存,大小不定也不會自動釋放。使用二級緩存,生命周期與虛擬機的GC算法有關

當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法內定義的變量將會逐個放入這塊棧內存里,隨著方法的執行結束,這個方法的內存棧也將自然銷毀了。因此,所有在方法中定義的變量都是放在棧內存中的;棧中存儲的是基礎變量以及一些對象的引用變量,基礎變量的值是存儲在棧中,而引用變量存儲在棧中的是指向堆中的數組或者對象的地址,這就是為何修改引用類型總會影響到其他指向這個地址的引用變量。

當我們在程序中創建一個對象時,這個對象將被保存到運行時數據區中,以便反復利用(因為對象的創建成本通常較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨方法的結束而銷毀,即使方法結束后,這個對象還可能被另一個引用變量所引用(方法的參數傳遞時很常見),則這個對象依然不會被銷毀,只有當一個對象沒有任何引用變量引用它時,系統的垃圾回收機制才會在核實的時候回收它。

2. 賦值、淺拷貝、深拷貝

  • 對于基本類型值,賦值、淺拷貝、深拷貝時都是復制基本類型的值給新的變量,之后二個變量之間操作不在相互影響。
  • 對于引用類型值,分以下三個方面:
    • 賦值后二個變量指向同一個地址,一個變量改變時,另一個也同樣改變;
    • 淺拷貝后得到一個新的變量,這個與之前的已經不是指向同一個變量,改變時不會使原數據中的基本類型一同改變,但會改變會原數據中的引用類型數據
    • 深拷貝后得到的是一個新的變量,她的改變不會影響元數據
- 和原數據是否指向同一對象 第一層數據為基本數據類型 原數據中包含子對象
賦值 改變會使原數據一同改變 改變會使原數據一同改變
淺拷貝 改變不會使原數據一同改變 改變會使原數據一同改變
深拷貝 改變不會使原數據一同改變 改變不會使原數據一同改變
    var obj1 = {
        'name' : 'zhangsan',
        'age' :  '18',
        'language' : [1,[2,3],[4,5]],
    };

    var obj2 = obj1;

    var obj3 = shallowCopy(obj1);
    function shallowCopy(src) {
        var dst = {};
        for (var prop in src) {
            if (src.hasOwnProperty(prop)) {
                dst[prop] = src[prop];
            }
        }
        return dst;
    }

    obj2.name = "lisi";
    obj3.age = "20";

    obj2.language[1] = ["二","三"];
    obj3.language[2] = ["四","五"];

    console.log(obj1);  
    //obj1 = {
    //    'name' : 'lisi',
    //    'age' :  '18',
    //    'language' : [1,["二","三"],["四","五"]],
    //};

    console.log(obj2);
    //obj2 = {
    //    'name' : 'lisi',
    //    'age' :  '18',
    //    'language' : [1,["二","三"],["四","五"]],
    //};

    console.log(obj3);
    //obj3 = {
    //    'name' : 'zhangsan',
    //    'age' :  '20',
    //    'language' : [1,["二","三"],["四","五"]],
    //};

2.1淺拷貝

數組常用的淺拷貝方法slice(),concat(),Array.from(),以及es6的解構

var arr1 = [1, 2,{a:1,b:2,c:3,d:4}];
var arr2 = arr1.slice();
var arr3 = arr1.concat();
var arr4 = Array.from(arr1);
var arr5 = [...arr1];
arr2[0]=2;
arr2[2].a=2;
arr3[0]=3;
arr3[2].b=3;
arr4[0]=4;
arr4[2].c=4;
arr5[0]=5;
arr5[2].d=5;
// arr1[1,2,{a:2,b:3,c:4,d:5}]
// arr2[2,2,{a:2,b:3,c:4,d:5}]
// arr3[3,2,{a:2,b:3,c:4,d:5}]
// arr4[4,2,{a:2,b:3,c:4,d:5}]
// arr5[5,2,{a:2,b:3,c:4,d:5}]

對象常用的淺拷貝方法Object.assign(),es6解構

var obj1 = {
    x: 1, 
    y: {
        m: 1
    }
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.x=2;
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}

我們自己實現一個淺拷貝

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
var shallowCopy = function(obj) {
    // 只拷貝對象
    if (typeof obj !== 'object') return;
    // 根據obj的類型判斷是新建一個數組還是對象
    var newObj = obj instanceof Array ? [] : {};
    // 遍歷obj,并且判斷是obj的屬性才拷貝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

2.2. 深拷貝

比較簡單粗暴的的做法是使用JSON.parse(JSON.stringify(obj))

var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse( JSON.stringify(arr) );
new_arr[4].old=4;
console.log(arr); //['old', 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr); //['old', 1, true, ['old1', 'old2'], {old: 4}]

JSON.parse(JSON.stringify(obj)) 看起來很不錯,不過 MDN文檔 的描述有句話寫的很清楚:

undefined、任意的函數以及 symbol 值,在序列化過程中會被忽略(出現在非數組對象的屬性值中時)或者被轉換成 null(出現在數組中時)。

但是在平時的開發中JSON.parse(JSON.stringify(obj))已經滿足90%的使用場景了。

下面我們自己來實現一個

var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;
}

3. 參數的傳遞

所有的函數參數都是按值傳遞。也就是說把函數外面的值賦值給函數內部的參數,就和把一個值從一個變量賦值給另一個一樣;

  • 基本類型
var a = 2;
function add(x) {
 return x = x + 2;
}
var result = add(a);
console.log(a, result); // 2 4
  • 引用類型
function setName(obj) {
  obj.name = 'laowang';
  obj = new Object();
  obj.name = 'Tom';
}
var person = new Object();
setName(person);
console.log(person.name); // laowang

很多人錯誤地以為在局部作用域中修改的對象在全局作用域中反映出來就是說明參數是按引用傳遞的。
但是通過上面的例子可以看出如果person是按引用傳遞的最終的person.name應該是Tom。
實際上當函數內部重寫obj時,這個變量引用的就是一個局部變量了。而這個變量會在函數執行結束后銷毀。(這是是在js高級程序設計看到的,還不是很清楚)

4. 判斷方法

基本類型用typeof,引用類型用instanceof

特別注意typeof null"object", null instanceof Objecttrue;

console.log(typeof "Nicholas"); // "string"
console.log(typeof 10);         // "number"
console.log(typeof true);       // "boolean"
console.log(typeof undefined);  // "undefined"
console.log(typeof null);      // "object"

var items = [];
var obj = {};
function reflect(value){
  return value;
}

console.log(items instanceof Array); // true;
console.log(obj instanceof Object); // true;
console.log(reflect instanceof Function); // true;

Object.prototype.toString.call([]).slice(8, -1)有興趣的同學可以看一下這個是干什么的

5. 總結

JS 數據類型

閱讀原文

看完文章,還有福利拿哦,往下看??????
感興趣的小伙伴可以在公號【grain先森】后臺回復【190315】獲取【Css 參考規范】,可以轉發朋友圈和你的朋友分享哦。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,120評論 1 32
  • 1.設計模式是什么? 你知道哪些設計模式,并簡要敘述?設計模式是一種編碼經驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,172評論 0 12
  • 面試題參考1 : 面試題[http://www.cocoachina.com/ios/20150803/12872...
    江河_ios閱讀 1,752評論 0 4
  • 介紹一下Objective-c常用的函數,常數變量算術函數【算術函數】 函數名說明 int rand()隨機數生成...
    噬尾蛇閱讀 242評論 0 1
  • 2017.5.12 滿全 打卡 感謝大家的認真欣賞! 感謝伙伴們的一起成長! 今天看到這個寫作要求時,我就想到...
    王者甘閱讀 100評論 0 0