谈一谈对象的深拷贝与浅拷贝、同步与异步的理解

对象的浅拷贝与深拷贝

我们可以用一个简单的例子来说明浅拷贝和深拷贝的区别。

假设有一个原始的对象 obj,它有一个属性 name 和一个引用类型属性 bodybody 又包含了身高、体重和血型三个属性。对象的结构如下:

const obj = {
  name: 'Tom',
  body: {
    height: 180,
    weight: 70,
    bloodType: 'A'
  }
}

浅拷贝

浅拷贝使用 Object.assign() 或者展开运算符 ... 进行复制,它会复制对象本身的属性值,但对于对象中的对象或数组等引用类型的属性值,它只是将其引用地址复制了一份。这就意味着,新对象和原对象的引用类型属性其实是同一个对象。

下面是浅拷贝的例子:

javascriptCopy code
const shallowCopy = Object.assign({}, obj);
// 或者使用展开运算符
// const shallowCopy = { ...obj };

现在 shallowCopy 是一个新的对象,它和 obj 具有相同的属性和属性值。我们可以在 shallowCopy 中修改身高的值:

arduinoCopy code
shallowCopy.body.height = 190;

这时,obj 对象的身高属性也会发生变化,因为 shallowCopyobj 其实共享同一个身体信息对象。可以使用 console.log 来查看它们之间的关系:

arduinoCopy code
console.log(shallowCopy.body === obj.body); // true

深拷贝

深拷贝会递归地将原对象中的所有引用类型的属性值都复制一份,这样就可以得到一个与原对象完全独立的新对象,修改新对象中的引用类型属性不会影响原对象中的属性值。

下面是深拷贝的例子:

javascriptCopy code
const deepCopy = JSON.parse(JSON.stringify(obj));

这里使用了 JSON 序列化和反序列化来进行深拷贝。JSON.stringify() 方法可以将对象转换为字符串,而 JSON.parse() 方法则可以将字符串转换为对象,这样就得到了一个全新的对象。

现在我们可以在 deepCopy 中修改身高的值:

arduinoCopy code
deepCopy.body.height = 200;

这时,obj 对象的身高属性不会受到影响,因为 deepCopyobj 的身体信息对象是两个不同的对象,它们互相独立。可以使用 console.log 来查看它们之间的关系:

arduinoCopy code
console.log(deepCopy.body === obj.body); // false

希望这个例子能帮助你更好地理解浅拷贝和深拷贝。

同步与异步

在 JavaScript 中,同步和异步是两种不同的代码执行模式。

同步代码是按照代码的书写顺序依次执行,每一行代码都要等待上一行代码执行完毕后才能执行,直到所有的代码都执行完毕,程序才能继续往下执行。同步代码会阻塞后面代码的执行,如果前面的代码执行时间很长,会导致整个程序运行变慢,甚至出现假死的情况。

异步代码则不同,它是在后台执行,不会阻塞主线程,当异步操作完成后,会将结果返回给主线程,主线程再去执行对应的回调函数。异步代码一般使用回调函数、Promise、async/await 等方式来实现。

JavaScript 中常见的异步操作包括:

  1. 定时器:使用 setTimeoutsetInterval 方法可以在指定的时间后执行某个函数,例如:

    javascriptCopy code
    console.log('start');
    setTimeout(() => {
      console.log('after 2 seconds');
    }, 2000);
    console.log('end');
    

    上面的代码中,setTimeout 方法会在 2 秒后执行回调函数,但是主线程不会阻塞,继续执行下面的代码。

  2. 回调函数:在异步操作完成后,会将结果作为参数传递给回调函数进行处理。例如:

    javascriptCopy code
    function getData(callback) {
      setTimeout(() => {
        const data = { name: 'Tom', age: 18 };
        callback(data);
      }, 2000);
    }
    
    console.log('start');
    getData((data) => {
      console.log(data);
    });
    console.log('end');
    

    上面的代码中,getData 函数会在 2 秒后返回一个数据对象,并将数据对象作为参数传递给回调函数进行处理。

  3. Promise:使用 Promise 可以更方便地处理异步操作,可以通过 then 方法注册成功的回调函数,通过 catch 方法注册失败的回调函数,例如:

    javascriptCopy code
    function getData() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const data = { name: 'Tom', age: 18 };
          resolve(data);
        }, 2000);
      });
    }
    
    console.log('start');
    getData().then((data) => {
      console.log(data);
    }).catch((error) => {
      console.log(error);
    });
    console.log('end');
    

    上面的代码中,getData 函数返回一个 Promise 对象,可以使用 then 方法注册成功的回调函数,使用 catch 方法注册失败的回调函数。当 Promise 对象的状态发生变化时,对应的回调函数会被执行。

异步代码的优势在于它可以提高程序的响应速度,避免阻塞主线程,提升用户体验。但是在编写异步代码时,需要注意异步代码的执行顺序,避免出现意外的结果。

原文链接:https://juejin.cn/post/7214400156594569275 作者:二木同学_

(0)
上一篇 2023年3月26日 下午5:11
下一篇 2023年3月26日 下午5:21

相关推荐

发表回复

登录后才能评论