资讯专栏INFORMATION COLUMN

也来探讨一下Object.assign

kuangcaibao / 744人阅读

摘要:如果值为或,它将创建并返回一个空对象,否则,它将返回一个对应于给定值的对象。如果该值已经是一个对象,它将返回该值。此方法不会更改现有的数组,而是返回一个新的数组。所以我们可以使用递归实现一个下面就直接贴代码了,略啰嗦,欢迎拍砖

Object.assign 是什么?

此处直接复制mdn文档的内容如下:

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

翻译一下也就是:

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它会返回目标对象。

为了便于理解,此处贴出mdn的对Object.assign的polyfill

if (typeof Object.assign != "function") {
  // Must be writable: true, enumerable: false, configurable: true
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) { // .length of function is 2
      "use strict";
      if (target == null) { // TypeError if undefined or null
        throw new TypeError("Cannot convert undefined or null to object");
      }

      var to = Object(target);

      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource != null) { // Skip over if undefined or null
          for (var nextKey in nextSource) {
            // Avoid bugs when hasOwnProperty is shadowed
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}

其中的Object构造函数为给定的值创建一个对象包裹器。如果值为null或undefined,它将创建并返回一个空对象,否则,它将返回一个Type对应于给定值的对象。如果该值已经是一个对象,它将返回该值。
举个栗子?

Object(1)
// Number {1}
Object("")
// String {"", length: 0}
Object(false)
// Boolean {false}

从polyfill的代码不难看出,Object.assign 就是将所传参数当中的对象的可枚举属性的值覆盖到第一个对象上,那么由于js当中的object,array是引用类型,所以对与对象,数组的覆盖其实只是覆盖了对数组,对象的引用,也即 浅copy

mdn栗子来一枚

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
如何实现深copy?

来个redux 当中reducer 嵌套数据更新的栗子?

add(state, { payload: todo }) {
      const todos = state.a.b.todos.concat(todo);
      const b = Object.assign({},state.a.b,{todos})
      const a = Object.assign({},state.a,{b});
      return Object({},state,{a});
    },

上面的栗子当中concat()方法用于合并两个或多个数组。此方法不会更改现有的数组,而是返回一个新的数组。可以理解为利用concat方法创建了一个新的todos数组,这样就可以避免对数据的修改影响到了旧的todos数组,然后将新的todos数组使用Object.assign 给新的b,以此,仅仅实现了sate对象中将深层次的todos的一个‘深copy’。
但是如果state还有其他的属性的值为对象或者数组,简单的使用Object.assign 只是复制了一个引用。所以在写reducer的时候需要尽量避免state嵌套的太深,为了安全,我们可以使用 updeep来更新数据,或者直接使用不可变数据,此处不再多说,继续探讨Object.assign.

实现一个deepCopy?
前面探讨了对象当中单个属性值的深copy,但是如果有多个值,怎么办呢?一个一个手动找出来?当然不行啊,这样一点儿也不好玩儿
为了实现一个deepCopy,我们先简单了解一下js的数据类型:
值类型:数值、布尔值、null、undefined。

基本类型值是指在栈内存保存的简单数据段,在复制基本类型值的时候,会开辟出一个新的内存空间,将值复制到新的内存空间,举个栗子:

var a = 1;
var b = a;
a = 2;
console.log(a);//输出2;
console.log(b);//输出1;
引用类型:对象、数组、函数等。

用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址,举个栗子:

var a={b:1}
var a2 = a;
a2.b = 2;
console.log(a)  // 输出 {b: 2}
deepCopy

了解了js的数组类型之后,那么实现一个深copy其实主要就是解决引用类型的copy,数组和对象无限往下拆,最终其属性也是值类型组成的。所以我们可以使用递归实现一个deepCopy,下面就直接贴代码了,略啰嗦,欢迎?拍砖

function detectType(source) {
    return Object.prototype.toString
        .call(source)
        .split(/[[,s,]]/)[2]
        .toLowerCase();
}
function deepCopy(source, copyDeep) {
    var type = detectType(source);
    if (!(type === "object" || type === "array")) {
        return source;
    }
    var newObject = type === "array" ? source.slice() :Object.assign({}, source);
    if (!copyDeep) {
        return newObject;
    }
    Object.keys(newObject).forEach(function (key) {
        newObject[key] = deepCopy(newObject[key], true);
    });
    return newObject;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107322.html

相关文章

  • JavaScript·随记 深拷贝 vs. 浅拷贝

    摘要:而在这个运算符的相关用例中,往往会涉及到其他知识点,深拷贝和浅拷贝就是其中之一。即对象的浅拷贝会对主对象的值进行拷贝,而该值有可能是一个指针,指向内存中的同一个对象。,可以看到深拷贝和浅拷贝是对复制引用类型变量而言的。 在ES6的系列文章中,基本都会提到Spread——扩展运算符(...)。而在这个运算符的相关用例中,往往会涉及到其他知识点,深拷贝和浅拷贝就是其中之一。 背景知识 在讨...

    RyanQ 评论0 收藏0
  • 也来谈谈RPC

    摘要:前言,顾名思义即远程过程调用,可以说是分部式应用的基础,也是概念中的核心部分。对于来说,可以分为之间的调用与和其他平台之间的调用。和分别代表了这两种模式。 前言 RPC,顾名思义即远程过程调用,可以说是分部式WEB应用的基础,也是SOA概念中的核心部分。对于J2EE来说,可以分为JVM之间的调用与和其他平台之间的调用。前者主要是RMI,而后者则五花八门,比如Apache的Thrift...

    NSFish 评论0 收藏0

发表评论

0条评论

kuangcaibao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<