javascript _.assign 仅当目标对象中存在属性时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28104798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 08:25:38  来源:igfitidea点击:

_.assign only if property exists in target object

javascriptlodash

提问by sparty02

My need is to do something like an _.assign, but only if the target object already has the property being assigned. Think of it like the source objects may have some properties to contribute, but also some properties that I don't want to mix in.

我需要做类似 _.assign 的事情,但前提是目标对象已经分配了属性。把它想象成源对象可能有一些属性可以贡献,但也有一些我不想混入的属性。

I haven't ever used _.assign's callback mechanism, but tried the following. It 'worked', but it still assigned the property to the dest object (as undefined). I don't want it to assign at all.

我从未使用过 _.assign 的回调机制,但尝试了以下方法。它“有效”,但它仍然将该属性分配给 dest 对象(未定义)。我根本不希望它分配。

_.assign(options, defaults, initial, function (destVal, sourceVal) {
  return typeof destVal == 'undefined' ? undefined : sourceVal;
});

I wrote the following function to do this, but wondering if lodash already has something baked in that is more elegant.

我写了下面的函数来做到这一点,但想知道 lodash 是否已经有一些更优雅的东西。

function softMerge (dest, source) {
    return Object.keys(dest).reduce(function (dest, key) {
      var sourceVal = source[key];

      if (!_.isUndefined(sourceVal)) {
        dest[key] = sourceVal;
      }

      return dest;
    }, dest);
}

回答by ne8il

You could take just the keys from the first object

你可以只从第一个对象中取出钥匙

var firstKeys = _.keys(options);

Then take a subset object from the second object, taking only those keys which exist on the first object :

然后从第二个对象中获取一个子集对象,只获取第一个对象上存在的那些键:

var newDefaults = _.pick(defaults, firstKeys);

Then use that new object as your argument to _.assign:

然后使用该新对象作为您的参数_.assign

_.assign(options, newDefaults);

Or in one line :

或者在一行中:

_.assign(options, _.pick(defaults, _.keys(options)));

Seemed to work when I tested it here : http://jsbin.com/yiyerosabi/1/edit?js,console

我在这里测试时似乎有效:http: //jsbin.com/yiyerosabi/1/edit?js,console

回答by Ciantic

Here is a immutable deep version, I call it "merge that retains the shape", in TypeScript that uses lodash:

这是一个不可变的深度版本,我称之为“保留形状的合并”,在使用 lodash 的 TypeScript 中:

function _mergeKeepShapeArray(dest: Array<any>, source: Array<any>) {
    if (source.length != dest.length) {
        return dest;
    }
    let ret = [];
    dest.forEach((v, i) => {
        ret[i] = _mergeKeepShape(v, source[i]);
    });
    return ret;
}

function _mergeKeepShapeObject(dest: Object, source: Object) {
    let ret = {};
    Object.keys(dest).forEach((key) => {
        let sourceValue = source[key];
        if (typeof sourceValue !== "undefined") {
            ret[key] = _mergeKeepShape(dest[key], sourceValue);
        } else {
            ret[key] = dest[key];
        }
    });
    return ret;
}

function _mergeKeepShape(dest, source) {
    // else if order matters here, because _.isObject is true for arrays also
    if (_.isArray(dest)) {
        if (!_.isArray(source)) {
            return dest;
        }
        return _mergeKeepShapeArray(dest, source);
    } else if (_.isObject(dest)) {
        if (!_.isObject(source)) {
            return dest;
        }
        return _mergeKeepShapeObject(dest, source);
    } else {
        return source;
    }
}

/**
 * Immutable merge that retains the shape of the `existingValue`
 */
export const mergeKeepShape = <T>(existingValue: T, extendingValue): T => {
    return _mergeKeepShape(existingValue, extendingValue);
}

And a simple test to see how I vision such merge should work:

还有一个简单的测试,看看我认为这种合并应该如何工作:

let newObject = mergeKeepShape(
    {
        a : 5,
        // b is not here
        c : 33,
        d : {
            e : 5,
            // f is not here
            g : [1,1,1],
            h : [2,2,2],
            i : [4,4,4],
        }
    },
    {
        a : 123,
        b : 444,
        // c is not here
        d : {
            e : 321,
            f : 432,
            // g is not here
            h : [3,3,3],
            i : [1,2],
        }
    }
);
expect(newObject).toEqual({
    a : 123,
    // b is not here
    c : 33,
    d : {
        e : 321,
        // f is not here,
        g : [1,1,1],
        h : [3,3,3],
        i : [4,4,4]
    }
});

I used seamless-immutable myself in the test, but didn't see a need to put it in this answer.

我在测试中自己使用了无缝不可变,但认为没有必要将它放在这个答案中。

I hereby place this in the Public Domain.

我在此将其置于公共领域。

回答by svarog

Another way to accomplish this is by combining _.mapObjectwith _.has

实现此目的的另一种方法是结合_.mapObject使用_.has

_.mapObject(object1, function(v, k) {
    return _.has(object2, k) ? object2[k] : v;
});

Explanation:

解释:

  1. Traverse all key/value pairs of object1using _.mapObject
  2. Using _.has, check if property name kalso exists in object2.
  3. If it does, copy the value assigned to key object2's kback to object1, else, just return the existing value of object1 (v).
  1. 遍历object1using 的所有键/值对_.mapObject
  2. 使用_.has,检查属性名称是否k也存在于object2.
  3. 如果是这样,复制分配给按键值object2kobject1,否则,只是返回的object1现有的值(v)。

Plunkr

普朗克