资讯专栏INFORMATION COLUMN

JavaScript复制(合并)对象

vslam / 2010人阅读

摘要:实现合并对象的方法有很多种,比如也是用写的,谢谢系列等,至于区别自己看文档,文档地址打造的一个不可变数据结构库的方法其中,为原生方法,但是存在以下两个在具体应用场景上的缺点浏览器兼容性问题只能进行浅合并关于浅合并深合并,码友之述备矣,这里就

javascript实现合并对象的方法有很多种,比如:

1、Object.assign

2、jQuery.extend(jQuery也是用javascript写的,谢谢)

3、lodash系列(lodash.merge、lodash.assign等,至于区别自己看文档,文档地址:https://lodash.com/docs)

4、Immutable.js(fackbook打造的一个不可变数据结构JS库)的 merge 方法

其中,Object.assign为javascript原生方法,但是存在以下两个在具体应用场景上的缺点:

1、浏览器兼容性问题

2、只能进行浅合并(关于浅合并深合并,码友之述备矣,这里就不赘言,戳:https://juejin.im/entry/58df4...)

PS: 之所以说具体应用场景的缺点,是因为假如项目是在高版本浏览器运行,并且只要对数据结构进行浅合并,那就不存在上述两个问题

而为了实现合并对象,特意引入上述的 jQuery、lodash、immutable这些库,就有点夸张了(项目本身需要用到这些库,那当我什么也没说)

好了,进入正题,下面是我自己实现的一个可配置的合并多个对象的方法

function EXT(options) {
    return new EXT.prototype.init(options);
}

EXT.fn = EXT.prototype = {
    type: function(o) {
        return Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
    },
    typeMap: {
        object: function() {
            return {};
        },
        array: function() {
            return [];
        }
    },
    // 默认配置项
    defaults: {
        // 是否深合并
        isDeep: true,
        // 是否遍历合并源对象原型链上的属性
        includePrototype: true,
        // 用于对每个合并项进行自定义修正
        forEach: function(target, name, sourceItem) {
            target[name] = sourceItem;
            return target;
        }
    },
    // 将配置项合并到默认配置项
    init: function(options) {
        for (let name in options) {
            this.defaults[name] = options[name];
        }
        return this;
    },
    merge: function() {
        let self = this,
            _default = self.defaults,
            i = 1,
            length = arguments.length,
            target = arguments[0] || {},
            source,
            targetItem,
            sourceItem,
            tiType,
            siType,
            clone,
            name;

        for (; i < length; i++) {
            // 判断源对象是否为空
            if ((source = arguments[i]) != null) {
                for (name in source) {
                    const hasPro = source.hasOwnProperty(name);
                    // 是否遍历源对象的原型链
                    if (hasPro || _default.includePrototype) {
                        targetItem = target[name];
                        sourceItem = source[name];
                        tiType = self.type(targetItem);
                        siType = self.type(sourceItem);

                        // 防止出现回环
                        if (target === sourceItem) {
                            continue;
                        }

                        // 如果复制的是对象或者数组
                        if (_default.isDeep && sourceItem != null && self.typeMap[siType]) {
                            clone = targetItem != null && tiType === siType ? targetItem : self.typeMap[siType]();
                            // 递归
                            target[name] = self.merge(clone, sourceItem);
                        } else {
                            clone = hasPro ? target : target.__proto__;
                            // 处理每一个合并项
                            clone = _default.forEach.call(self, clone, name, sourceItem);
                        }
                    }
                }
            }
        }
        return target;
    }
};
EXT.fn.init.prototype = EXT.fn;

撸个demo先,先定义两份数据

function Foo() {
    this.a = 1;
}

function Bar() {
    this.c = 3;
}

Foo.prototype.b = 2;
Bar.prototype.d = 4;

let data = {
    info: {
        name: "Leslie",
        age: 26,
        scores: [60, 66, 70, 80]
    }
};
let data2 = {
    info: {
        name: "Leslie",
        age: 32,
        scores: [99, 66, 70, {
            name: "john",
            age: 18
        },
        new Foo()]
    }
};

1、普通合并
let target = EXT().merge(data1, data2);

结果为:

2、自定义配置进行合并

isDeep:选择是否进行深合并,设置为 false 则只进行浅合并,默认为 true

let target = EXT({ isDeep: false }).merge(data1, data2);

includePrototype:选择是否要遍历对象的原型链,默认为 true

let target = EXT({ includePrototype: false }).merge(data1, data2);

forEach:对每个合并项进行自定义处理

let target = EXT({
    forEach: function(target, name, sourceItem) {
        target[name] = sourceItem + ’hello, 自定义每个合并项‘;
        return target;
    }
}).merge(data1, data2);

好了,这就是这个方法的全部,还不知道怎么用的小伙伴可以私信我.

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

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

相关文章

  • [译] 为什么原型继承很重要

    摘要:使用构造函数的原型继承相比使用原型的原型继承更加复杂,我们先看看使用原型的原型继承上面的代码很容易理解。相反的,使用构造函数的原型继承像下面这样当然,构造函数的方式更简单。 五天之前我写了一个关于ES6标准中Class的文章。在里面我介绍了如何用现有的Javascript来模拟类并且介绍了ES6中类的用法,其实它只是一个语法糖。感谢Om Shakar以及Javascript Room中...

    xiao7cn 评论0 收藏0
  • JavaScript合并数组的方法

    摘要:添加元素到数组合并两个数组错误方法应该用方法,将被的数组当成参数数组。会改变数组,返回最新属性,占用内存较少。 一、Array.prototype.concat() concat方法将创建一个新的数组,然后将调用它的对象(this指向的对象)中的元素以及所有参数中的数组类型的参数中的元素以及非数组类型的参数本身按照顺序放入这个新数组,并返回该数组。concat方法并不修改调用它的对象...

    econi 评论0 收藏0
  • JavaScript深入理解对象方法——Object.assign()

    摘要:它将返回目标对象。该方法使用源对象的和目标对象的,所以它会调用相关和。注意,会跳过那些值为或的源对象。合并对象注意目标对象自身也会改变。注意,只有字符串的包装对象才可能有自身可枚举属性。,第三个源对象更是不会被拷贝到的。 Object.assign() Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。 语法 Object.a...

    sunnyxd 评论0 收藏0
  • JavaScript专题之从零实现jQuery的extend

    摘要:不过的实现中,多了很多细节上的判断,比如第一个参数是否是布尔值,是否是一个对象,不传参数时的默认值等。 JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 extend 函数 前言 jQuery 的 extend 是 jQuery 中应用非常多的一个函数,今天我们一边看 jQuery 的 extend 的特性,一边实现一个 extend! extend 基本用...

    wangtdgoodluck 评论0 收藏0
  • JavaScript深拷贝、浅拷贝

    摘要:深拷贝浅拷贝浅拷贝浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅拷贝出来的对象也会相应改变。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成。 JavaScript深拷贝、浅拷贝 浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅拷贝出来的对象也会相应改变。 深拷贝:开辟了一块新的内存存放地址和地址指向的对象,原地址的任何对象改变了,深拷...

    Scorpion 评论0 收藏0

发表评论

0条评论

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