面试官想要的 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阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,036评论 1 32
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,057评论 0 12
  • 面试题参考1 : 面试题[http://www.cocoachina.com/ios/20150803/12872...
    江河_ios阅读 1,626评论 0 4
  • 介绍一下Objective-c常用的函数,常数变量算术函数【算术函数】 函数名说明 int rand()随机数生成...
    噬尾蛇阅读 222评论 0 1
  • 2017.5.12 满全 打卡 感谢大家的认真欣赏! 感谢伙伴们的一起成长! 今天看到这个写作要求时,我就想到...
    王者甘阅读 90评论 0 0