【问题标题】:How do I parse a string to number while destructuring?解构时如何将字符串解析为数字?
【发布时间】:2019-03-16 06:35:57
【问题描述】:

我正在尝试围绕解构分配进行试验。现在我有一个案例,我试图解决自身的解构问题。

例如,我有这样的输入:

let input = {latitude: "17.0009", longitude: "82.2108"}

其中latitude 和longitude 键值是字符串,但我想在解构时将它们解析为数字。

let input = {latitude: "17.0009", longitude: "82.2108"}
let {latitude,longitude} = input

console.log(typeof latitude,typeof longitude)

我可以在babel repl 中看到这需要一个对象的引用,然后访问每个键。所以上面的代码是一样的:

"use strict";

 var arr = {
   latitude: "17.0009",
   longitude: "82.2108"
  };
 var latitude = arr.latitude,
     longitude = arr.longitude;

我想做一些事情,比如使用解构语法本身。

"use strict";

var arr = {
  latitude: "17.0009",
  longitude: "82.2108"
};
var latitude = Number(arr.latitude),
    longitude = Number(arr.longitude);

我也乐于看到一些黑客行为。

更新

我可以用, 运算符提出一个技巧:

let arr = {latitude: "17.0009", longitude: "82.2108"}

let {lat,lng} = ({latitude,longitude} = arr, ({lat:+latitude,lng:+longitude}))

console.log(typeof lat, typeof lng)

附注:-你必须阅读 Moritz Roessler's answer这是hacky但包含很好的知识和信息

【问题讨论】:

  • let input = {latitude: "17.0009"- 0, longitude: "82.2108"- 0} 虽然实际上解构表达式不允许只赋值。允许之前或之后...
  • @zer00ne 但我无法更改输入,例如将其视为来自第三方。
  • 输入作为函数的返回怎么样?
  • take this as reference 我想做的是 {lat:+lat,lng:+lng} 到 {lat,lng} 如果我能够解构并将其解析为数字
  • 返回时好像有类型转换

标签: javascript ecmascript-6 destructuring


【解决方案1】:

解构只是从对象和数组中解压缩属性并将它们分配给变量的好方法。正如问题中的转译代码所暗示的那样,任何类型的操作都是不可能的。

一个hack是创建另外 2 个变量(input 中不存在)并将 default value 设置为与先前解构属性等效的数字:

let input = { latitude: "17.0009", longitude: "82.2108" }
let { latitude, longitude, lat = +latitude, long = +longitude } = input

console.log(typeof latitude, typeof longitude, typeof lat, typeof long)

代码大约翻译成这个(Babel):

var latitude = input.latitude,
    longitude = input.longitude,
    lat = input.lat === undefined ? +latitude : input.lat,
    long = input.long === undefined ? +longitude : input.long;

它只是利用了创建变量和分配属性值的顺序。同样,这仅在input 中没有lat 或long 属性时才有效。否则,它将失败三元条件,lat 将被设置为input.lat。


这样的东西会更容易阅读:

let { latitude, longitude } = input;
let lat = +latitude, 
    long = +longitude;

或

let [ lat, long ] = [ +latitude, +longitude ]

【讨论】:

  • 感谢您的想法 :) 是的,这就是我所做的,但使用 , 运算符的可读性较差
  • 如果我们能let { +latitude } = …就更好了
  • @Alhadis 是的,它会很好。但在目前的实施情况下,这是不可能的。因为当你进行嵌套解构lat obj = {a:{b:{c:'some'}}}; let {a:{b:c}} = obj 它与let c = obj.a.b.c 相同,所以如果你使用+ 介于两者之间的某个位置,你将无法访问属性
  • 我喜欢这个,它也允许使用const。
【解决方案2】:

您可以解构这些值,获取一个值数组并映射该值的新数据类型,然后将该值分配回变量。

let input = { latitude: "17.0009", longitude: "82.2108" },
    { latitude, longitude} = input;

[latitude, longitude] = [latitude, longitude].map(Number);

console.log(typeof latitude, latitude);
console.log(typeof longitude, longitude);

【讨论】:

    【解决方案3】:

    你可以有一个可重复使用的函数,如下所示:

    const numberInputs = input =>
        Object.keys(input).reduce((acc, val) => {
            acc[val] = +input[val];
            return acc;
        }, {});
    

    然后重复使用它...

    然后做:

    let {latitude,longitude} = numberInputs(input);
    
    console.log(typeof latitude,typeof longitude) //number //number
    

    得到17.0009 和82.2108 作为数字...

    这样您也可以保留您的原始对象并制作一个副本...这样您就可以拥有以数字为值的对象的原始和副本...

    【讨论】:

    • 感谢您的意见。正如您在更新中看到的那样,我可以使用, 运算符和解构来完成它。但我很难将 in map arr.map((/Here i am trying to do the same what i am able to do with comma operatore/) => {}) 纳入其中吗?
    【解决方案4】:

    虽然您不能在解构表达式本身中执行类型转换,但可能的替代/解决方法是在函数的参数中解构属性,然后返回一个包含新类型的数组。

    例如,如下所示:

    const input = {latitude: "17.0009", longitude: "82.2108"}
    const [lat, lng] = (({latitude:a, longitude:b}) => [+a, +b])(input);
    
    console.log(typeof lat, typeof lng); // number number

    但是,对于这样的事情,我不会使用解构,可能会使用常规的点表示法:

    const input = {latitude: "17.0009", longitude: "82.2108"}
    const lat = +input.latitude;
    const lng = +input.longitude;
    
    console.log(typeof lat, typeof lng); // number number

    【讨论】:

    • 感谢您的意见。正如您在更新中看到的那样,我可以使用, 运算符和解构来完成它。但我很难将地图中的 arr.map((/我在这里尝试做与逗号操作符/) => {} 相同的事情,你能帮忙吗?
    • 提高可读性优于 hacky 快捷方式 - 您的代码的其他用户和未来您会感谢您的。现代转译器将为您完成所有缩小。那么为什么不写成人类可读的形式呢?
    • @CodeManiac 嗯,我想不出任何办法,但似乎 adiga 有,我认为他们的解决方案就是你所追求的
    • @NickParsons 是的,伙计,他的回答比我正在做的, operator hack 更干净
    【解决方案5】:

    这是不可能的 - 在解构期间不能对属性执行任何操作。如果您使用解构将属性提取到变量中,则该变量将=== 变为原始属性值。

    (当然,您可以在解构之前将原始对象的值转换为数字,但这不是一回事)

    【讨论】:

    • 是的,这已经有问题了。如果你能想出一些技巧,我可以看看周围的一些技巧吗?
    【解决方案6】:

    使用String.prototype 上定义的 getter 作为辅助函数,有一种超级 hacky 的方法。

    (你可能不想这样做)

    Object.defineProperty (String.prototype, "asNumber",{
       get: function () { return +this}
    });
    let input = {latitude: "17.0009", longitude: "82.2108"}
    let {latitude:{asNumber:latitude},
         longitude: {asNumber:longitude}} = input
    
    console.log (latitude, longitude)

    让我们把它分解成更简单的步骤。

    //Extending the `String` prototype means every string 
    //will have access to the defined property  via 
    //its prototype, so
    String.prototype.foo = function () {return `${this}.foo\`} 
    //means you can now call foo() like any other string method
    "bar".foo() //"bar.foo"`
    
    //A getter allows you to define a function that acts 
    //as a property which will be executed upon access. 
    let obj = {get getter () {console.log ('Hi');}}
    obj.getter // Hi
    
    //Combine those two and you can call functions by 
    //accessing properties of strings. 
    Object.defineProperty (String.prototype, "asNumber",{
       get: function () { return +this}
    });
    
    //Now that you have a property that is available at 
    //every string - and make it execute a function; you 
    //can convert a string to a number, simply by
    //accessing a property
    "42".asNumber //42
    
    //To make that work with destructuring assignment, 
    //you need to know about another handy feature. You 
    //can assign destructured properties to a new 
    //variable name.
    let {a:b, b:a} = {a:'a', b:'b'};
    a; //'b'
    b; //'a'
    
    //Since you can nest destructuring assignments, and 
    //every string implicitly has a 'asNumber' property, 
    //you can destructure that property as well. 
    
    let {lat: {asNumber}} = {lat: "42"};
    asNumber //42
    
    //The last thing to know is, there's apparently 
    //nothing wrong with using an existing variable as 
    //new name for a destructured property. So you can 
    //just use the `asNumber` property from the 
    //prototype and assign it to the same variable  
    //you destructured from the object.
    let {lat: {asNumber: lat}} = {lat: "42"};
    lat; //42
    

    使用同名没有什么问题,因为在let块的作用域中只会引入最后一个变量名

    【讨论】:

    • 是的,我不想要,但仍然喜欢看到更多关于它的解释
    • @CodeManiac Sure (: 很高兴看到人们对该语言感兴趣。我添加了解释
    • 不能要求任何更好的解释 :) 这个解释包含了很多知识
    • 但我想知道一件事let {a : {b}} = {'a' : {'b': 'some value }},这里的嵌套解构将b 捕获为some value。比let {lat: {asNumber}} = {lat: "42"}; 是如何捕获的?还是和let {lat:asNumber} = {lat} = {lat: "42"};一样?
    • @CodeManiac 是的,完全一样,它们是一样的! (:
    【解决方案7】:

    如果你不介意使用lodash,你可以试试这个:

    import { mapValues } from 'lodash';
    
    const input = {latitude: "17.0009", longitude: "82.2108"}
    const {latitude, longitude} = mapValues(input, Number);
    

    【讨论】:

      【解决方案8】:

      我可能会进行设置,以便我关心的每个“对象类型”都有一个对应的“解析器类型”:一个具有相同键的对象,但其值是每个成员的适当解析函数。

      像这样:

      "use strict";
      
      var arr = {
          latitude: "17.0009",
          longitude: "82.2108"
      };
      
      function Parser(propParsers)
      {
          this.propParsers = propParsers;
          this.parse = function (obj) {
              var result = {};
              var propParsers = this.propParsers;
              Object.keys(obj).forEach(function (k) {
                  result[k] = propParsers[k](obj[k]);
              });
              return result;
          };
      }
      
      var parser = new Parser({
          latitude: Number,
          longitude: Number
      });
      
      let {latitude,longitude} = parser.parse(arr);
      console.log(latitude);
      console.log(longitude);

      【讨论】:

        猜你喜欢
        • 2018-10-20
        • 2016-01-06
        • 2012-07-25
        • 1970-01-01
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多