js中赋值、浅拷贝和深拷贝

重点:

 

一、单线程

js引擎是单线程,模拟多线程(短时间内轮流执行多个任务的片段)

步骤:

1.切分任务

2.将任务随机排列,组成队列

3.按顺序将任务片段送进js进程

4.js线程执行任务片段

 

二、数据类型

  • 基本数据类型的特点:直接存储在栈(stack)中的数据
  • 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

1.原始值是不可改变的,原因如下:

var a = 3;
var b = a;
a = 1;
console.log(a); // 1
console.log(b); // 3

var a = 3;

var b = a;

a = 1;

 

2.引用值在堆栈中的存放

引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里 

var arr1 = [1,2,3,4,5];
var arr2 = arr1;

arr1.push(5);
console.log(arr1); // [1,2,3,4,5,5]
console.log(arr2); // [1,2,3,4,5,5]

arr1 = [1,2];
console.log(arr1); // [1,2]
console.log(arr2); // [1,2,3,4,5,5]

var arr1 = [1,2,3,4,5];

var arr2 = arr1;

当arr1.push(5);时,arr2会跟着arr1一起变化

arr1 = [1,2]

arr1重新赋值,arr2不会跟着改变

 

三、赋值

赋值:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

var obj1 = {
    a: 1,
    b: 2,
    c: [3,4,5],
    d: function() { console.log(000); }
}
var obj2 = obj1;
obj2.a = 6;
console.log(obj1); //{a: 6, b: 2, c: Array(3), d: ƒ}
console.log(obj2); //{a: 6, b: 2, c: Array(3), d: ƒ}

四、浅拷贝

浅拷贝:创建一个新对象。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。 

var obj1 = {
    a: 1,
    b: 2,
    c: [3,4,5],
    d: function() { console.log(000); }
}

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

var obj2 = shallowCopy(obj1);
obj2.a = 6;

obj2.c[0] = 7;

console.log(obj1); //{a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); //{a: 6, b: 2, c: [7,4,5], d: ƒ}

浅拷贝方法:

1.如上的属性复制方法

2.Object.saaign():

var obj1 = {
    a: 1,
    b: 2,
    c: [3,4,5],
    d: function() { console.log(000); }
}

var obj2 = Object.assign({}, obj1);
obj2.a = 6;
obj2.c[0] = 7; // 浅拷贝
console.log(obj1); // {a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); // {a: 6, b: 2, c: [7,4,5], d: ƒ}

obj2.c = [8,9,0]; // 
console.log(obj1); // {a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); // {a: 6, b: 2, c: [8,9,0], d: ƒ}

3.如果是数组,可使用Array.prototype.concat()和Array.prototype.slice(),这两个方法都不修改原数组

Array.prototype.concat():

var arr1 = [1,[2,3,4],5];
var arr2 = arr1.concat();

arr2[0] = 6;
arr2[1][0] = 7;

console.log(arr1); //[1,[7,3,4],5]
console.log(arr2); //[6,[7,3,4],5]

Array.prototype.slice():

var arr1 = [1,[2,3,4],5];
var arr2 = arr1.slice();

arr2[0] = 6;
arr2[1][0] = 7;

console.log(arr1); //[1,[7,3,4],5]
console.log(arr2); //[6,[7,3,4],5]

 

五、深拷贝

 1.JSON.parse(JSON.stringify()):用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。                               

可以实现数组或对象深拷贝,但不能处理函数    

var obj1 = {
    a: 1,
    b: 2,
    c: [3,4,5],
    d: function() { console.log(000); }
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.lpg(obj2); // {a: 1, b: 2, c:[3,4,5]} //d中的函数直接被略去

2.手写递归方法:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

//定义检测数据类型的功能函数
    function checkedType(target) {
      return Object.prototype.toString.call(target).slice(8, -1)
    }
    //实现深度克隆---对象/数组
    function clone(target) {
      //判断拷贝的数据类型
      //初始化变量result 成为最终克隆的数据
      let result, targetType = checkedType(target)
      if (targetType === 'Object') {
        result = {}
      } else if (targetType === 'Array') {
        result = []
      } else {
        return target
      }
      //遍历目标数据
      for (let i in target) {
        //获取遍历数据结构的每一项值。
        let value = target[i]
        //判断目标结构里的每一值是否存在对象/数组
        if (checkedType(value) === 'Object' ||
          checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
          //继续遍历获取到value值
          result[i] = clone(value)
        } else { //获取到value值是基本的数据类型或者是函数。
          result[i] = value;
        }
      }
      return result
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章