美文网首页
js底层数据类型

js底层数据类型

作者: sponing | 来源:发表于2017-09-05 00:36 被阅读0次

js底层数据类型

堆和栈的区别

其实深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同。

堆和栈都是内存中划分出来用来存储的区域。

栈(stack)为自动分配的内存空间,它由系统自动释放;而堆(heap)则是动态分配的内存,大小不定也不会自动释放。


  • 只能在一端(称为栈顶(top))对数据项进行插入和删除。

    先进后出(FILO—First-In/Last-Out)。

    由操作系统自动分配释放</br>
    栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

    引用类型值可变

    引用类型是可以直接改变其值的,例如:

    var a = [1,2,3];
    a[1] = 5;
    console.log(a[1]); // 5
    
    引用类型的比较是引用的比较

    所以每次我们对 js 中的引用类型进行操作的时候,都是操作其对象的引用(保存在栈内存中的指针),所以比较两个引用类型,是看其的引用是否指向同一个对象。例如:

    var a = [1,2,3];
    var b = [1,2,3];
    console.log(a === b); // false
    

    虽然变量 a 和变量 b 都是表示一个内容为 1,2,3 的数组,但是其在内存中的位置不一样,也就是说变量 a 和变量 b 指向的不是同一个对象,所以他们是不相等的。

    传值与传址

    函数的参数是按值传递
    不懂看看这篇文字javascript高级教程技术之第四章 变量 作用域和内存问题

    了解了基本数据类型与引用类型的区别之后,我们就应该能明白传值与传址的区别了。在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。例如:

    var a = 10;
    var b = a;
    
    a ++ ;
    console.log(a); // 11
    console.log(b); // 10
    

    所以说,基本类型的赋值的两个变量是两个独立相互不影响的变量。

    但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。例如:

    var a = {}; // a保存了一个空对象的实例
    var b = a;  // a和b都指向了这个空对象
    
    a.name = 'jozo';
    console.log(a.name); // 'jozo'
    console.log(b.name); // 'jozo'
    
    b.age = 22;
    console.log(b.age);// 22
    console.log(a.age);// 22
    
    console.log(a == b);// true
    

    浅拷贝

    在深入了解之前,我认为上面的赋值就是浅拷贝,哇哈哈,真的是图样图森破。上面那个应该只能算是“引用”,并不算是真正的浅拷贝。
    一下部分参照知乎中的提问: javascript中的深拷贝和浅拷贝

    赋值(=)和浅拷贝的区别

    那么赋值和浅拷贝有什么区别呢,我们看下面这个例子:

        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,[4,5]],
        //};
    
        console.log(obj2);
        //obj2 = {
        //    'name' : 'lisi',
        //    'age' :  '18',
        //    'language' : [1,[4,5]],
        //};
    
        console.log(obj3);
        //obj3 = {
        //    'name' : 'zhangsan',
        //    'age' :  '20',
        //    'language' : [1,[4,5]],
        //};
    

    先定义个一个原始的对象 obj1,然后使用赋值得到第二个对象 obj2,然后通过浅拷贝,将 obj1 里面的属性都赋值到 obj3 中。也就是说:

    • obj1:原始数据
    • obj2:赋值操作得到
    • obj3:浅拷贝得到

    然后我们改变 obj2 的 name 属性和 obj3 的 name 属性,可以看到,改变赋值得到的对象 obj2 同时也会改变原始值 obj1,而改变浅拷贝得到的的 obj3 则不会改变原始对象 obj1。这就可以说明赋值得到的对象 obj2 只是将指针改变,其引用的仍然是同一个对象,而浅拷贝得到的的 obj3 则是重新创建了新对象。

    然而,我们接下来来看一下改变引用类型会是什么情况呢,我又改变了赋值得到的对象 obj2 和浅拷贝得到的 obj3 中的 language 属性的第二个值和第三个值(language 是一个数组,也就是引用类型)。结果见输出,可以看出来,无论是修改赋值得到的对象 obj2 和浅拷贝得到的 obj3 都会改变原始数据。

    这是因为浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。所以就会出现改变浅拷贝得到的 obj3 中的引用类型时,会使原始数据得到改变。

    深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象,

    浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象

    深拷贝

    看了这么半天,你也应该清楚什么是深拷贝了吧,如果还不清楚,我就剖腹自尽(ಥ_ಥ)

    深拷贝是对对象以及对象的所有子对象进行拷贝。

    那么问题来了,怎么进行深拷贝呢?

    思路就是递归调用刚刚的浅拷贝,把所有属于对象的属性类型都遍历赋给另一个对象即可。我们直接来看一下 Zepto 中深拷贝的代码:

    // 内部方法:用户合并一个或多个对象到第一个对象
        // 参数:
        // target 目标对象  对象都合并到target里
        // source 合并对象
        // deep 是否执行深度合并
        function extend(target, source, deep) {
            for (key in source)
                if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
                    // source[key] 是对象,而 target[key] 不是对象, 则 target[key] = {} 初始化一下,否则递归会出错的
                    if (isPlainObject(source[key]) && !isPlainObject(target[key]))
                        target[key] = {}
    
                    // source[key] 是数组,而 target[key] 不是数组,则 target[key] = [] 初始化一下,否则递归会出错的
                    if (isArray(source[key]) && !isArray(target[key]))
                        target[key] = []
                    // 执行递归
                    extend(target[key], source[key], deep)
                }
                // 不满足以上条件,说明 source[key] 是一般的值类型,直接赋值给 target 就是了
                else if (source[key] !== undefined) target[key] = source[key]
        }
    
        // Copy all but undefined properties from one or more
        // objects to the `target` object.
        $.extend = function(target){
            var deep, args = slice.call(arguments, 1);
    
            //第一个参数为boolean值时,表示是否深度合并
            if (typeof target == 'boolean') {
                deep = target;
                //target取第二个参数
                target = args.shift()
            }
            // 遍历后面的参数,都合并到target上
            args.forEach(function(arg){ extend(target, arg, deep) })
            return target
        }
    

    在 Zepto 中的 $.extend 方法判断的第一个参数传入的是一个布尔值,判断是否进行深拷贝。

    在 $.extend 方法内部,只有一个形参 target,这个设计你真的很巧妙。
    因为形参只有一个,所以 target 就是传入的第一个参数的值,并在函数内部设置一个变量 args 来接收去除第一个参数的其余参数,如果该值是一个布尔类型的值的话,说明要启用深拷贝,就将 deep 设置为 true,并将 target 赋值为 args 的第一个值(也就是真正的 target)。如果该值不是一个布尔类型的话,那么传入的第一个值仍为 target 不需要进行处理,只需要遍历使用 extend 方法就可以。

    参考文章:

相关文章

  • js底层数据类型

    js底层数据类型 堆和栈的区别 其实深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同。 堆和栈都是内存中划分出...

  • Vue一些问题汇总!你值得看看

    vue的底层原理? vue组件之间的通信? JS中判断数据类型的方法有几种? 最常见的判断方法:typeof 判断...

  • vue常见问题

    vue的底层原理? vue组件之间的通信? JS中判断数据类型的方法有几种? 最常见的判断方法:typeof 判断...

  • JS的类型转换

    JS的数据类型: 首先, JS的数据类型分为基本数据类型和引用数据类型基本数据类型: string number ...

  • js对象数组的深拷贝方法以及其他方法

    js判断数据类型是否为对象 js判断数据类型是否为数组

  • 2022前端面试题汇总(附答案)更新中

    JS相关 1.JS中的数据类型 (1)数据类型分为基本数据类型和引用数据类型基本数据类型:number、null、...

  • js深拷贝

    在写深拷贝之前,有必要说一下js的数据类型 一.js数据类型 1.1 分类 js数据类型分为两类:原始数据类型、引...

  • js数据类型

    JS基本数据类型和引用数据类型(JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝) 再讲 js 的基本数据类...

  • 判断数据类型

    typeof 用于判断非对象的基本数据类型u哦这function类型原理:在js底层中,采用低位存储了变量的类型信...

  • js入门知识点

    * 基础知识 * js的输出方式 * js的组成 * js的命名规范 * 数据类型 * number数据类型 * ...

网友评论

      本文标题:js底层数据类型

      本文链接:https://www.haomeiwen.com/subject/zuiyjxtx.html