如何在解构时将字符串解析为数字?
How do I parse a string to number while destructuring?
我正在尝试围绕解构赋值进行试验。现在我有一个案例,我试图应对解构本身。
例如,我有这样的输入:
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 的回答 这是 hacky 但包含很好的知识和信息
这是不可能的 - 在解构期间不能对 属性 执行任何操作。如果您使用解构将 属性 提取到变量中,则该变量将 ===
到原始 属性 值。
(当然,您可以在解构之前将原始对象的值转换为 Number,但这不是一回事)
虽然您不能在解构表达式本身内执行类型转换,但可能 alternative/workaround 可以解构函数参数中的属性,然后 return 具有新类型的数组在里面。
例如,如下所示:
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
您可以有一个 可重复使用的函数 ,如下所示:
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
作为数字...
这样你也可以保留你的原始对象并制作一个副本...所以你同时拥有以数字作为值的对象的原始和副本...
解构是从对象和数组中解压属性并将它们分配给变量的好方法。正如问题中的编译代码所暗示的那样,任何类型的操作都是不可能的。
一个 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 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);
使用在 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 块的作用域
我可能会设置一些东西,以便我关心的每个 "object type" 都有一个对应的 "parser type":一个具有相同键的对象,但其值是每个成员的适当解析函数。
像这样:
"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);
如果您不介意使用 lodash
,您可以试试这个:
import { mapValues } from 'lodash';
const input = {latitude: "17.0009", longitude: "82.2108"}
const {latitude, longitude} = mapValues(input, Number);
我正在尝试围绕解构赋值进行试验。现在我有一个案例,我试图应对解构本身。
例如,我有这样的输入:
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 的回答 这是 hacky 但包含很好的知识和信息
这是不可能的 - 在解构期间不能对 属性 执行任何操作。如果您使用解构将 属性 提取到变量中,则该变量将 ===
到原始 属性 值。
(当然,您可以在解构之前将原始对象的值转换为 Number,但这不是一回事)
虽然您不能在解构表达式本身内执行类型转换,但可能 alternative/workaround 可以解构函数参数中的属性,然后 return 具有新类型的数组在里面。
例如,如下所示:
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
您可以有一个 可重复使用的函数 ,如下所示:
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
作为数字...
这样你也可以保留你的原始对象并制作一个副本...所以你同时拥有以数字作为值的对象的原始和副本...
解构是从对象和数组中解压属性并将它们分配给变量的好方法。正如问题中的编译代码所暗示的那样,任何类型的操作都是不可能的。
一个 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 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);
使用在 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 块的作用域
我可能会设置一些东西,以便我关心的每个 "object type" 都有一个对应的 "parser type":一个具有相同键的对象,但其值是每个成员的适当解析函数。
像这样:
"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);
如果您不介意使用 lodash
,您可以试试这个:
import { mapValues } from 'lodash';
const input = {latitude: "17.0009", longitude: "82.2108"}
const {latitude, longitude} = mapValues(input, Number);