简体   繁体   English

比使用 Lodash 更好的获取属性的方法

[英]Better way to Get Property Than using Lodash

So we have this crap all over in our code, IMO too much lodash.所以我们的代码中到处都是这些废话,IMO 太多 lodash。 For example:例如:

const profileId = _.get(account, 'profileId', null);
const player = _.get(someCustomObject, 'player'); // Why??????  why not just someCustomObject.player?

is it me or is it ridiculous to be using lodash for everything when you can just access object properties by the object!当您只能通过对象访问对象属性时,是我还是将 lodash 用于所有内容是荒谬的! In general we're using lodash and it's overkill in many places and just makes the code way more verbose and hard to read when you have that all over.总的来说,我们使用 lodash,它在很多地方都是过大的,只是让代码变得更加冗长和难以阅读。

In this case, we don't really need lodash either:在这种情况下,我们也不需要 lodash:

const profileId = _.get(account, 'profileId', null);

what would be a way to do that without lodash?没有 lodash 有什么方法可以做到这一点? That's my question.这是我的问题。 Here are a few thoughts:这里有一些想法:

const profileId = (account && account.profileId) || null

any other ideas?还有其他想法吗?

UPDATE更新

Interesting, went with Ori's answer but just an observation here.有趣的是,按照 Ori 的回答,但只是在这里观察。 I wanted to remove defaulting the profileId to null just because I feel it's unecessary.我想删除默认的 profileId 为 null 只是因为我觉得这是不必要的。 But why didn't this set profileId to the account object?但是为什么这没有将 profileId 设置为帐户对象?

 const account = {}; const game = { player: 'Sam' } console.log(`account: ${account}`); const { profileId } = account || {}; const { player } = game || {}; console.log(`profileId: ${profileId} // why is this undefined if account has value {}???`); console.log(`player: ${player}`);

Even though account is set to a literal, I still get undefined for profileId above.即使 account 设置为文字,我仍然undefined为上面的 profileId undefined That's weird..?这很奇怪。。?

FINAL SOLUTION (run this in codepen.io since you'll need lodash loaded)最终解决方案(在codepen.io 中运行它,因为你需要加载 lodash)

console.log(" Example Clean Code without Lodash")
console.log('===============================')

let account = {};
const game = { player: 'Sam' }

console.log(`account: ${account}`);

const { profileId = null } = account;
const { player } = game || {};

console.log(`profileId: ${profileId}`);
console.log(`player: ${player}`);

/* using IIFE so profileId doesn't conflict with example above */
(() => {
  console.log("Example using unecessary Lodash")
  console.log('===============================')

  let profileId = _.get(account, 'profileId', null);
  const game = { player: 'Sam' } 

  console.log(`account2: ${account}`);

  const { player } = game || {};

  console.log(`profileId: ${profileId}`);
  console.log(`player: ${player}`);
})();

Lodash's _.get() is really good if you want to get something nested inside an object profile.player.id for example, and it also has a default if nothing is found or there's an error, like this example _.get(account, 'profileId', null); Lodash 的_.get()非常好,如果你想在对象profile.player.id嵌套一些东西,例如,如果没有找到任何东西或有错误,它也有一个默认值,就像这个例子_.get(account, 'profileId', null); . .

If it's a direct property of the object, you can use destructuring with a default :如果它是对象的直接属性,则可以使用具有默认值的解构

 const account = {}; const game = { player: 'Sam' } const { profileId = null } = account || {}; const { player } = game || {}; console.log(profileId); console.log(player);

A better solution might be the stage-1 proposal-optional-chaining if it makes it into the spec, although you can use it with a babel plugin right now:一个更好的解决方案可能是 stage-1 proposal-optional-chaining如果它进入规范,尽管你现在可以将它与 babel 插件一起使用:

const obj = {
  foo: {
    bar: {
      baz: 42,
    },
  },
};

const baz = obj?.foo?.bar?.baz; // 42

const safe = obj?.qux?.baz; // undefined

_.get is a helper method that is used for several reasons. _.get是一种辅助方法,用于多种原因。 It helps you reduce code/logic duplication, it's harder to make an error and easier to read and maintain your code.它可以帮助您减少代码/逻辑重复,更难出错并且更容易阅读和维护您的代码。

If you are worried about the performance difference between _.get and (account && account.profileId) || null如果您担心_.get(account && account.profileId) || null之间的性能差异(account && account.profileId) || null , I don't think you should be worried unless you have a huge codebase that calls _.get hundreads of times. (account && account.profileId) || null ,我不认为你应该担心,除非你有一个巨大的代码库调用_.get次。 Here is the lodash's get function definition and it's dependancies.这是 lodash 的get函数定义及其依赖项。

function get(object, path, defaultValue) {
  var result = object == null ? undefined : baseGet(object, path);
  return result === undefined ? defaultValue : result;
}

function baseGet(object, path) {
  path = castPath(path, object);

  var index = 0,
      length = path.length;

  while (object != null && index < length) {
    object = object[toKey(path[index++])];
  }
  return (index && index == length) ? object : undefined;
}

function castPath(value, object) {
  if (isArray(value)) {
    return value;
  }
  return isKey(value, object) ? [value] : stringToPath(toString(value));
}

function toKey(value) {
  if (typeof value == 'string' || isSymbol(value)) {
    return value;
  }
  var result = (value + '');
  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}

You can always perform a benchmark test for your code with 2 different variations and then decide if it makes enough difference for you to use the native implementation.您始终可以使用 2 个不同的变体对您的代码执行基准测试,然后确定它是否对您使用本机实现有足够的影响。

I just did a benchmark test where lodash's ._get was 95% slower than the native implementation.我刚刚做了一个基准测试,其中 lodash 的._get比本地实现慢95% I guess you can afford that unless your code heavily relies on ._get as stated above.我想你可以负担得起,除非你的代码严重依赖._get如上所述。 Maybe even better alternative would be to write your own helper function to get rid of the lodash's overhead and achieve the same pros of lodash's get and also near-native performance.也许更好的替代方法是写自己的辅助函数来摆脱lodash的开销,实现lodash的相同利弊get和也接近本机的性能。 You can define your own helper function knowing in advance what kind of data will be passed to it, thus writing a zero-overhead helper for your specific usecase.您可以定义自己的辅助函数,提前知道将传递给它的数据类型,从而为您的特定用例编写零开销的辅助函数。

Here is a nice one-liner from the article " Safely Accessing Deeply Nested Values In JavaScript "这是文章“ Safely Accessing Deeply Nested Values In JavaScript ”中的一个很好的单行代码

export function _get(object, path, defval = null) {
    if (typeof path === "string") path = path.split(".");
    return path.reduce((xs, x) => (xs && xs[x] ? xs[x] : defval), object);
}

You may also use this awesome library of zero dependency utilities https://github.com/angus-c/just您也可以使用这个很棒的零依赖实用程序库https://github.com/angus-c/just

This come out from a recent discussion:这来自最近的讨论:

var template = "string with {obj.prop} first of 0: {results[0].first}";
var data = {obj: {prop: 'mine'}, results:[{first:'f'},{first:'ff'}] }
var regex = /{(.*?)}/g;
var str = template.replace(regex, (e, key) => _.get(data, key, ''));
console.log(str);

but you can write a function:但是你可以写一个函数:

const interpolate = (template, data) => template.replace(/{(.*?)}/g, (e, key) => _.get(data, key, ''));

of cource it is simpler to use:当然使用起来更简单:

let str = interpolate("string with {obj.prop} first of 0: {results[0].first}", data)

in general in everywhere you do not know what you are going to replace, _.get() is something good to have.一般来说,在你不知道要替换什么的地方, _.get() 是个好东西。

UPDATE : fix the missing regexp!更新:修复丢失的正则表达式!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM