JavaScript与jQuery的等价物';s扩展法 背景

JavaScript与jQuery的等价物';s扩展法 背景,javascript,jquery,object,extend,Javascript,Jquery,Object,Extend,我有一个函数,它将config对象作为参数。在函数中,我还有default对象。这些对象中的每一个都包含一些属性,这些属性基本上用作函数中其余代码的设置。为了避免必须指定config对象中的所有设置,我使用jQuery的extend方法填充一个新对象settings,如果default对象中没有指定default对象中的任何默认值: var config = {key1: value1}; var default = {key1: default1, key2: default2, key 3:

我有一个函数,它将
config
对象作为参数。在函数中,我还有
default
对象。这些对象中的每一个都包含一些属性,这些属性基本上用作函数中其余代码的设置。为了避免必须指定
config
对象中的所有设置,我使用jQuery的
extend
方法填充一个新对象
settings
,如果
default
对象中没有指定
default
对象中的任何默认值:

var config = {key1: value1};
var default = {key1: default1, key2: default2, key 3: default 3};

var settings = $.extend(default, config);

//resulting properties of settings:
settings = {key1: value1, key2: default2, key 3: default 3};
问题 这非常有效,但我希望在不需要jQuery的情况下复制此功能。有没有一种同样优雅(或接近)的方法可以用普通的ol'javascript实现这一点


编辑:非重复对正
这项质询并非与“”项质询重复。尽管这个问题只是想创建一个包含来自两个独立对象的所有键和值的对象,但我特别想说明在两个对象共享一些键而不是所有键的情况下如何执行此操作,以及在存在重复键的情况下,哪个对象将获得结果对象的优先级(默认值)。更具体地说,我想讨论如何使用jQuery的方法来实现这一点,并找到一种不用jQuery的替代方法。虽然两个问题的许多答案重叠,但这并不意味着问题本身是相同的。

要在代码中获得结果,您可以执行以下操作:

function extend(a, b){
    for(var key in b)
        if(b.hasOwnProperty(key))
            a[key] = b[key];
    return a;
}
请记住,使用的扩展方式将修改默认对象。如果你不想那样,就用

$.extend({}, default, config)
模仿jQuery功能的更健壮的解决方案如下:

function extend(){
    for(var i=1; i<arguments.length; i++)
        for(var key in arguments[i])
            if(arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}
函数扩展(){

对于(var i=1;i,您可以使用
for
语句循环对象的属性

var settings = extend(default, config);

function extend(a, b){
    var c = {};
    for(var p in a)
        c[p] = (b[p] == null) ? a[p] : b[p];
    return c;
}

当我使用纯javascript开发时,它对我帮助很大

function extends(defaults, selfConfig){
     selfConfig = JSON.parse(JSON.stringify(defaults));
     for (var item in config) {
         if (config.hasOwnProperty(item)) {
             selfConfig[item] = config[item];
         }
     }
     return selfConfig;
}
还可以进行调整以创建新的对象原型:

Object.prototype.extend = function(b){
for(var key in b)
    if(b.hasOwnProperty(key))
        this[key] = b[key];
    return this;
}

var settings = default.extend(config);

您可以使用Object.assign

var defaults = {key1: "default1", key2: "default2", key3: "defaults3"};
var config = {key1: "value1"};

var settings = Object.assign({}, defaults, config); // values in config override values in defaults
console.log(settings); // Object {key1: "value1", key2: "default2", key3: "defaults3"}
它将所有可枚举自身属性的值从一个或多个源对象复制到目标对象,并返回目标对象

Object.assign(target, ...sources)
它适用于除IE以外的所有桌面浏览器(但包括Edge)。 它减少了移动支持

你自己看看这里:

关于深度复制 但是,Object.assign没有jQuery的extend方法所具有的deep选项

注意:不过,您通常可以使用JSON实现类似的效果

var config = {key1: "value1"};
    var defaults = {key1: "default1", key2: "default2", keyDeep: {
        kd1: "default3",
        kd2: "default4"
    }};
    var settings = JSON.parse(JSON.stringify(Object.assign({}, defaults, config))); 
    console.log(settings.keyDeep); // Object {kd1: "default3", kd2: "default4"}

这是我在尝试消除jQuery依赖关系时提出的一种与深度复制略有不同的方法。它主要是为小而设计的,因此可能没有人们期望的所有功能。应该完全兼容ES5(从IE9开始,由于使用):


我很乐意收到有关此实现的反馈或评论。提前感谢!

我更喜欢使用我的通用ForEach,并且不会损坏第一个对象的代码:

function forEachIn(obj, fn) {
    var index = 0;
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            fn(obj[key], key, index++);
        }
    }
}

function extend() {
    var result = {};
    for (var i = 0; i < arguments.length; i++) {
        forEachIn(arguments[i],
            function(obj, key) {
                result[key] = obj;
            });
    }
    return result;
}
您可以使用ECMA 2018

var-config={key1:value1};
var default={key1:default1,key2:default2,key3:default3};
变量设置={…默认值,…配置}
//设置的结果属性:
设置={key1:value1,key2:default2,key3:default3};

只是偷用jQuery的方法:-PGood idea@RocketHazmat,注意如果你复制该函数,它还有一些其他jQuery依赖项,比如
jQuery.isPlainObject
jQuery.isFunction
@RocketHazmat有人已经做过了:这不会考虑
a
中不存在的属性。尽管它是n在示例中,
$.extend
实际上是这样工作的,它合并了所有对象的所有属性。当我阅读jquery基本代码时,它实际上执行了一个递归函数来复制或克隆值。因此它是深度克隆/复制,而不仅仅是像上面的代码那样在第一级复制。我希望看到一个代码示例,可能是fiddle,因为e plain js非常酷,但是非常抽象,非常感谢。这不会像$.extend doesYeah那样递归,但在这里它从默认值跳过了key1,而没有将其添加到新对象中。@Anonymous确实添加了它,但它被配置数组中的key1值覆盖。我认为这是真的。所以,它毕竟没有添加它第一个问题:
parse(stringify(X))==X
。第二个问题:“deep”意味着值为对象的键也将被递归合并。因此,为了证明这一点,您应该使用类似于
const a={X:{a:1},y:2};const b={X:{b:2},y:3};
,并验证
deep(a,b)={x:{a:1,b:2},y:3}
,这正是jQuery deep所做的。这是目前为止最好的答案。它进行深度复制,不会损坏第一个对象,支持无限对象,并且可以在扩展时更改类型(即,这里的许多答案不会将字符串扩展到对象,这个答案会)。这是我书中的每一个复选标记。完全扩展替换,非常容易理解。这是最整洁、最干净的方法!执行深度复制吗?
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',
  });
});
function forEachIn(obj, fn) {
    var index = 0;
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            fn(obj[key], key, index++);
        }
    }
}

function extend() {
    var result = {};
    for (var i = 0; i < arguments.length; i++) {
        forEachIn(arguments[i],
            function(obj, key) {
                result[key] = obj;
            });
    }
    return result;
}
obj1 = extend(obj1, obj2);