Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript中深拷贝和浅拷贝(新增浅比较) #9

Open
qppq54s opened this issue May 16, 2019 · 0 comments
Open

JavaScript中深拷贝和浅拷贝(新增浅比较) #9

qppq54s opened this issue May 16, 2019 · 0 comments

Comments

@qppq54s
Copy link
Owner

qppq54s commented May 16, 2019

为什么会有浅拷贝和深拷贝

在js里,将对象赋值给一个新的变量:

var a = {a: 1, b: 2};
var b = a;
a===b; // true

因为a和b指向同一个内存地址,所以它们完全相同,而且改变其中一个,另一个也会改变。

在一些情境下,我们需要拷贝一个全新的对象,防止对原对象产生影响。

浅拷贝

常见的浅拷贝方法

$.extend({}, obj);
Array.prototype.slice();
Object.assign(); // let b = {...a}也一样
function shallowCopy(src) {
  var dst = {};
  for(var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}

可以看出来,浅拷贝就是对象的第一层key-value的复制,对于value值为简单数据类型的可以做到与原对象互不影响。
如果是复杂的对象,浅拷贝还是不能解决之前提到的问题,这时候就需要深拷贝

深拷贝

常见的深拷贝方法

function deepClone(source){
    // 先判断是否为对象
    if(!source || typeof source !== 'object'){
      throw new Error('请传入参数对象');
    }
    // 创建空的对象和数组
    let targetObj = Array.isArray(source) ? [] : {};
    // 如果value是简单数据类型,把对象的key-value拷贝到新的对象
    // 如果value是对象, 递归调用方法,把对象最终解析到基本数据类型
    for (let keys of Object.keys(source)) {
        if(source[keys] && typeof source[keys] === 'object'){
            targetObj[keys] = deepClone(source[keys]);
          }else{
            targetObj[keys] = source[keys];
          }
    }
    return targetObj;
 }

function deepClone(source){
  return JSON.parse(JSON.stringify(source));
}

相对的,既然有深/浅拷贝,就会有深/浅比较

严格/浅比较 (strictEqual / shallowEqual)

严格比较

严格比较由JavaScript语言本身提供 ===

function strictEqual(a, b) {
  return a === b
}

浅比较

这里我们引用react-redux里的源码

const hasOwn = Object.prototype.hasOwnProperty

// is方法可以判断基本数据类型是否相等
function is(x, y) {
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y    // 排除 -0 === 0 返回 true的情况
  } else {
    return x !== x && y !== y    // 排除NaN === NaN 返回 false的情况
  }
}

// 浅比较(看上去一样)
export default function shallowEqual(objA, objB) {
  // 首先对基本数据类型做比较
  if (is(objA, objB)) return true

  // 基本类型比较完成后,判断参数是否为对象,如果不是直接返回false,因为typeof null是object但null
     的情况在is方法里可以判断,所以也直接返回false
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false
  }

  const keysA = Object.keys(objA)
  const keysB = Object.keys(objB)

  // 判断两个对象是否相同,可以先判断key的多少,不一样的肯定不同
  if (keysA.length !== keysB.length) return false

  // 递归判断每一层的key-value,此处与深拷贝类似
  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false
    }
  }

  return true
}
@qppq54s qppq54s changed the title JavaScript中深拷贝和浅拷贝 JavaScript中深拷贝和浅拷贝(新增浅比较) May 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant