JavaScript equivalent of jQuery's extend method

前端 未结 8 2044
小鲜肉
小鲜肉 2020-11-28 02:57

Background

I have a function that takes a config object as an argument. Within the function, I also have default object. Each of those

8条回答
  •  春和景丽
    2020-11-28 03:15

    This is my slightly different approach with deep copy I came up with while trying to eliminate a jQuery dependency. It is mostly designed for being small so it might have not all feature one expects. Should be fully ES5-compatible (starting from IE9 due to usage of Object.keys):

    function extend(obj1, obj2) {
        var keys = Object.keys(obj2);
        for (var i = 0; i < keys.length; i += 1) {
          var val = obj2[keys[i]];
          obj1[keys[i]] = ['string', 'number', 'array', 'boolean'].indexOf(typeof val) === -1 ? extend(obj1[keys[i]] || {}, val) : val;
        }
        return obj1;
      }
    

    You may wonder what the fifth line does exactly do ... If obj2.key is an object literal (i.e. if it's no ordinary type) we recursively call extend on it. If a property with that name doesn't exist in obj1 yet, we initialize it to an empty object first. Otherwise we simply set obj1.key to obj2.key.

    Here are some of my mocha/chai tests that should prove the common cases to work here:

    it('should extend a given flat object with another flat object', () => {
      const obj1 = {
        prop1: 'val1',
        prop2: 42,
        prop3: true,
        prop4: 20.16,
      };
      const obj2 = {
        prop4: 77.123,
        propNew1: 'newVal1',
        propNew2: 71,
      };
      assert.deepEqual(utils.extend(obj1, obj2), {
        prop1: 'val1',
        prop2: 42,
        prop3: true,
        prop4: 77.123,
        propNew1: 'newVal1',
        propNew2: 71,
      });
    });
    
    it('should deep-extend a given flat object with a nested object', () => {
      const obj1 = {
        prop1: 'val1',
        prop2: 'val2',
      };
      const obj2 = {
        propNew1: 'newVal1',
        propNew2: {
          propNewDeep1: 'newDeepVal1',
          propNewDeep2: 42,
          propNewDeep3: true,
          propNewDeep4: 20.16,
        },
      };
      assert.deepEqual(utils.extend(obj1, obj2), {
        prop1: 'val1',
        prop2: 'val2',
        propNew1: 'newVal1',
        propNew2: {
          propNewDeep1: 'newDeepVal1',
          propNewDeep2: 42,
          propNewDeep3: true,
          propNewDeep4: 20.16,
        },
      });
    });
    
    it('should deep-extend a given nested object with another nested object and deep-overwrite members', () => {
      const obj1 = {
        prop1: 'val1',
        prop2: {
          propDeep1: 'deepVal1',
          propDeep2: 42,
          propDeep3: true,
          propDeep4: {
            propDeeper1: 'deeperVal1',
            propDeeper2: 777,
            propDeeper3: 'I will survive',
          },
        },
        prop3: 'lone survivor',
      };
      const obj2 = {
        prop1: 'newVal1',
        prop2: {
          propDeep1: 'newDeepVal1',
          propDeep2: 84,
          propDeep3: false,
          propDeep4: {
            propDeeper1: 'newDeeperVal1',
            propDeeper2: 888,
          },
        },
      };
      assert.deepEqual(utils.extend(obj1, obj2), {
        prop1: 'newVal1',
        prop2: {
          propDeep1: 'newDeepVal1',
          propDeep2: 84,
          propDeep3: false,
          propDeep4: {
            propDeeper1: 'newDeeperVal1',
            propDeeper2: 888,
            propDeeper3: 'I will survive',
          },
        },
        prop3: 'lone survivor',
      });
    });
    

    I'd be happy about feedback or comments on this implementation. Thanks in advance!

提交回复
热议问题