Ran*_*lue 903 javascript functional-programming node.js map-function
我有一个对象:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个本机方法,类似于Array.prototype.map
将使用如下:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
Run Code Online (Sandbox Code Playgroud)
JavaScript是否具有map
对象的这种功能?(我想将它用于Node.JS,所以我不关心跨浏览器问题.)
Amb*_*mps 1331
没有原生map
的Object
对象,但这个怎么样:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
Object.keys(myObject).map(function(key, index) {
myObject[key] *= 2;
});
console.log(myObject);
// => { 'a': 2, 'b': 4, 'c': 6 }
Run Code Online (Sandbox Code Playgroud)
但您可以使用for ... in
以下方法轻松迭代对象:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
for (var key in myObject) {
if (myObject.hasOwnProperty(key)) {
myObject[key] *= 2;
}
}
console.log(myObject);
// { 'a': 2, 'b': 4, 'c': 6 }
Run Code Online (Sandbox Code Playgroud)
更新
很多人都提到以前的方法不返回新对象,而是操作对象本身.就此而言,我想添加另一个返回新对象的解决方案,并保留原始对象:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
// returns a new object with the values at each key mapped using mapFn(value)
function objectMap(object, mapFn) {
return Object.keys(object).reduce(function(result, key) {
result[key] = mapFn(object[key])
return result
}, {})
}
var newObject = objectMap(myObject, function(value) {
return value * 2
})
console.log(newObject);
// => { 'a': 2, 'b': 4, 'c': 6 }
console.log(myObject);
// => { 'a': 1, 'b': 2, 'c': 3 }
Run Code Online (Sandbox Code Playgroud)
Array.prototype.reduce
通过稍微将先前值与当前值合并,将数组减少为单个值.链由空对象初始化{}
.在每次迭代时,myObject
都会添加一个新的键,其正方形为值.
Rot*_*eti 266
如何在普通JS(ES6/ES2015)中使用即时变量赋值的单行程怎么样?
let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));
Run Code Online (Sandbox Code Playgroud)
使用reduce的另一个版本:
let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});
Run Code Online (Sandbox Code Playgroud)
作为函数的第一个例子:
const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));
// To square each value you can call it like this:
let mappedObj = oMap(myObj, (x) => x * x);
Run Code Online (Sandbox Code Playgroud)
如果要映射嵌套对象递归的功能性的风格,这是可以做到这样的:
const sqrObjRecursive = obj =>
Object.keys(obj).reduce(
(newObj, key) =>
obj[key] && typeof obj[key] === "object"
? { ...newObj, [key]: sqrObjRecursive(obj[key]) } // recurse.
: { ...newObj, [key]: obj[key] * obj[key] }, // square val.
{}
);
Run Code Online (Sandbox Code Playgroud)
或者更重要的是,像这样:
const sqrObjRecursive = obj => {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === "object") obj[key] = sqrObjRecursive(obj[key]);
else obj[key] = obj[key] * obj[key];
});
return obj;
};
Run Code Online (Sandbox Code Playgroud)
从ES7/ES2016开始,您可以使用Object.entries()
而不是Object.keys()
像这样:
let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));
Run Code Online (Sandbox Code Playgroud)
在极少数情况下,您可能需要映射类似于对象的对象,该对象在其原型链上包含继承对象的属性.在这种情况下Object.fromEntries()
将无法工作,因为Object.keys()
不会枚举继承的属性.如果需要映射继承的属性,则应使用Object.keys()
.
下面是一个继承另一个对象属性的对象示例,以及for (key in myObj) {...}
在这种情况下如何工作.
let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]));
Run Code Online (Sandbox Code Playgroud)
但是,请帮我一个忙,避免继承.:-)
Mar*_*rio 105
没有本地方法,但是lodash#mapValues可以很好地完成工作
_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
// ? { 'a': 3, 'b': 6, 'c': 9 }
Run Code Online (Sandbox Code Playgroud)
Aln*_*tak 57
写一个很容易:
Object.map = function(o, f, ctx) {
ctx = ctx || this;
var result = {};
Object.keys(o).forEach(function(k) {
result[k] = f.call(ctx, o[k], k, o);
});
return result;
}
Run Code Online (Sandbox Code Playgroud)
使用示例代码:
> o = { a: 1, b: 2, c: 3 };
> r = Object.map(o, function(v, k, o) {
return v * v;
});
> r
{ a : 1, b: 4, c: 9 }
Run Code Online (Sandbox Code Playgroud)
注意:此版本还允许您(可选)设置this
回调的上下文,就像Array
方法一样.
编辑 - 更改为删除使用Object.prototype
,以确保它不与map
对象上指定的任何现有属性冲突.
Mat*_*ens 25
您可以使用Object.keys
然后使用forEach
返回的键数组:
var myObject = { 'a': 1, 'b': 2, 'c': 3 },
newObject = {};
Object.keys(myObject).forEach(function (key) {
var value = myObject[key];
newObject[key] = value * value;
});
Run Code Online (Sandbox Code Playgroud)
或者以更模块化的方式:
function map(obj, callback) {
var result = {};
Object.keys(obj).forEach(function (key) {
result[key] = callback.call(obj, obj[key], key, obj);
});
return result;
}
newObject = map(myObject, function(x) { return x * x; });
Run Code Online (Sandbox Code Playgroud)
请注意,Object.keys
返回一个仅包含对象自己的可枚举属性的数组,因此它的行为类似于for..in
带有hasOwnProperty
检查的循环.
Ale*_*lls 18
这是直接的bs,JS社区中的每个人都知道它.有应该是这样的功能:
const obj1 = {a:4, b:7};
const obj2 = Object.map(obj1, (k,v) => v + 5);
console.log(obj1); // {a:4, b:7}
console.log(obj2); // {a:9, b:12}
Run Code Online (Sandbox Code Playgroud)
这是天真的实现:
Object.map = function(obj, fn, ctx){
const ret = {};
for(let k of Object.keys(obj)){
ret[k] = fn.call(ctx || null, k, obj[k]);
});
return ret;
};
Run Code Online (Sandbox Code Playgroud)
必须始终自己实现这一点非常烦人;)
如果你想要一些更复杂的东西,这不会干扰Object类,试试这个:
let map = function (obj, fn, ctx) {
return Object.keys(obj).reduce((a, b) => {
a[b] = fn.call(ctx || null, b, obj[b]);
return a;
}, {});
};
const x = map({a: 2, b: 4}, (k,v) => {
return v*2;
});
Run Code Online (Sandbox Code Playgroud)
但是将这个map函数添加到Object是安全的,只是不要添加到Object.prototype.
Object.map = ... // fairly safe
Object.prototype.map ... // not ok
Run Code Online (Sandbox Code Playgroud)
Joe*_*ron 17
我来到这里寻找并回答将对象映射到数组并得到此页面的结果.如果你来到这里寻找我的答案,这里是你如何映射和对象的数组.
您可以使用map从对象返回一个新数组,如下所示:
var newObject = Object.keys(myObject).map(function(key) {
return myObject[key];
});
Run Code Online (Sandbox Code Playgroud)
小智 12
接受的答案有两个缺点:
Array.prototype.reduce
,因为减少意味着改变复合类型的结构,在这种情况下不会发生.请注意,所有功能都以咖喱形式定义.
// small, reusable auxiliary functions
const keys = o => Object.keys(o);
const assign = (...o) => Object.assign({}, ...o);
const map = f => xs => xs.map(x => f(x));
const mul = y => x => x * y;
const sqr = x => mul(x) (x);
// the actual map function
const omap = f => o => {
o = assign(o); // A
map(x => o[x] = f(o[x])) (keys(o)); // B
return o;
};
// mock data
const o = {"a":1, "b":2, "c":3};
// and run
console.log(omap(sqr) (o));
console.log(omap(mul(10)) (o));
Run Code Online (Sandbox Code Playgroud)
o
重新分配.由于Javascript通过共享传递参考值,因此o
会生成一个浅表副本.我们现在能够o
在omap
不改变o
父范围的情况下进行变异.map
的返回值被忽略,因为map
执行了变异o
.由于这种副作用仍然存在于omap
父范围内并且在父范围内不可见,因此完全可以接受.这不是最快的解决方案,而是一个声明性和可重用的解决方案.这里的实现与单行,简洁但不太可读相同:
const omap = f => o => (o = assign(o), map(x => o[x] = f(o[x])) (keys(o)), o);
Run Code Online (Sandbox Code Playgroud)
ES2015指定了迭代器和可迭代协议.但是对象仍然不可迭代,因此无法映射.原因是数据和程序级别的混合.
JavaScript刚获得了新Object.fromEntries
方法。
function mapObject (obj, fn) {
return Object.fromEntries(
Object
.entries(obj)
.map(fn)
)
}
const myObject = { a: 1, b: 2, c: 3 }
const myNewObject = mapObject(myObject, ([key, value]) => ([key, value * value]))
console.log(myNewObject)
Run Code Online (Sandbox Code Playgroud)
上面的代码将Object转换为[[<key>,<value>], ...]
可映射的嵌套Array()。Object.fromEntries
将数组转换回对象。
这种模式的妙处在于,您现在可以轻松地在映射时考虑对象键。
Object.fromEntries
目前仅受这些浏览器/引擎支持,但是仍然可以使用polyfill(例如@ babel / polyfill)。
为了获得最佳性能
如果您的对象不经常更改但需要经常迭代,我建议使用本机Map作为缓存.
// example object
var obj = {a: 1, b: 2, c: 'something'};
// caching map
var objMap = new Map(Object.entries(obj));
// fast iteration on Map object
objMap.forEach((item, key) => {
// do something with an item
console.log(key, item);
});
Run Code Online (Sandbox Code Playgroud)
Object.entries已经在Chrome,Edge,Firefox和beta Opera中运行,因此它具有面向未来的功能.这是来自ES7所以polyfill它https://github.com/es-shims/Object.entries为IE它不起作用.
最小版本(es6):
Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})
Run Code Online (Sandbox Code Playgroud)
你可以使用map
方法和forEach
数组,但如果你想使用它,Object
那么你可以像下面这样使用它:
使用Javascript(ES6)
var obj = { 'a': 2, 'b': 4, 'c': 6 };
Object.entries(obj).map( v => obj[v[0]] *= v[1] );
console.log(obj); //it will log as {a: 4, b: 16, c: 36}
var obj2 = { 'a': 4, 'b': 8, 'c': 10 };
Object.entries(obj2).forEach( v => obj2[v[0]] *= v[1] );
console.log(obj2); //it will log as {a: 16, b: 64, c: 100}
Run Code Online (Sandbox Code Playgroud)
使用jQuery
var ob = { 'a': 2, 'b': 4, 'c': 6 };
$.map(ob, function (val, key) {
ob[key] *= val;
});
console.log(ob) //it will log as {a: 4, b: 16, c: 36}
Run Code Online (Sandbox Code Playgroud)
或者您可以使用其他循环,$.each
如下面的示例方法:
$.each(ob,function (key, value) {
ob[key] *= value;
});
console.log(ob) //it will also log as {a: 4, b: 16, c: 36}
Run Code Online (Sandbox Code Playgroud)
您只需使用以下命令即可将对象转换为数组:
您可以将对象值转换为数组:
myObject = { 'a': 1, 'b': 2, 'c': 3 };
let valuesArray = Object.values(myObject);
console.log(valuesArray);
Run Code Online (Sandbox Code Playgroud)
您可以将对象键转换为数组:
myObject = { 'a': 1, 'b': 2, 'c': 3 };
let keysArray = Object.keys(myObject);
console.log(keysArray);
Run Code Online (Sandbox Code Playgroud)
现在您可以执行普通的数组操作,包括 'map' 函数
小智 6
const array = Object.keys(object)
//returns all keys as array ["key", "key"]
const array = Object.values(object)
//returns all values as array ["value", "value"]
const array = Object.entries(object)
//returns all entries as array = [["key","value"], ["key","value"]]
Run Code Online (Sandbox Code Playgroud)
对结果使用 Map。
array.map()
Run Code Online (Sandbox Code Playgroud)
在map function
不存在的Object.prototype
,但是你可以模拟它像这样
var myMap = function ( obj, callback ) {
var result = {};
for ( var key in obj ) {
if ( Object.prototype.hasOwnProperty.call( obj, key ) ) {
if ( typeof callback === 'function' ) {
result[ key ] = callback.call( obj, obj[ key ], key, obj );
}
}
}
return result;
};
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
var newObject = myMap( myObject, function ( value, key ) {
return value * value;
});
Run Code Online (Sandbox Code Playgroud)
编辑:使用较新的 JavaScript 功能的规范方式是 -
const identity = x =>
x
const omap = (f = identity, o = {}) =>
Object.fromEntries(
Object.entries(o).map(([ k, v ]) =>
[ k, f(v) ]
)
)
Run Code Online (Sandbox Code Playgroud)
哪里o
是某个对象,f
是您的映射函数。或者我们可以说,给定一个函数 froma -> b
和一个值为 typea
的对象,生成一个值为 type 的对象b
。作为伪类型签名 -
// omap : (a -> b, { a }) -> { b }
Run Code Online (Sandbox Code Playgroud)
最初的答案是为了展示一个强大的组合器,mapReduce
它使我们能够以不同的方式思考我们的转换
m
,映射函数——让你有机会在之前转换传入的元素......r
,reduce函数——这个函数将累加器与映射元素的结果结合起来直观地,mapReduce
创建一个我们可以直接插入的新减速器Array.prototype.reduce
。但更重要的是,我们可以omap
通过使用对象 monoidObject.assign
和来简单地实现我们的对象函子实现{}
。
const identity = x =>
x
const omap = (f = identity, o = {}) =>
Object.fromEntries(
Object.entries(o).map(([ k, v ]) =>
[ k, f(v) ]
)
)
Run Code Online (Sandbox Code Playgroud)
请注意,我们实际上必须编写的程序的唯一部分是映射实现本身——
k => ({ [k]: f (o[k]) })
Run Code Online (Sandbox Code Playgroud)
也就是说,给定一个已知对象o
和一些 key k
,构造一个对象,其计算属性k
是调用f
键值的结果,o[k]
。
mapReduce
如果我们首先抽象,我们会看到它的测序潜力oreduce
// oreduce : (string * a -> string * b, b, { a }) -> { b }
const oreduce = (f = identity, r = null, o = {}) =>
Object
.keys (o)
.reduce
( mapReduce
( k => [ k, o[k] ]
, f
)
, r
)
// omap : (a -> b, {a}) -> {b}
const omap = (f = identity, o = {}) =>
oreduce
( mapReduce
( ([ k, v ]) =>
({ [k]: f (v) })
, Object.assign
)
, {}
, o
)
Run Code Online (Sandbox Code Playgroud)
一切都一样,但omap
现在可以在更高级别定义。当然,新的Object.entries
让这看起来很傻,但练习对学习者来说仍然很重要。
你不会看到mapReduce
这里的全部潜力,但我分享这个答案,因为看看它可以应用于多少地方很有趣。如果您对它的派生方式以及它可能有用的其他方式感兴趣,请参阅此答案。
归档时间: |
|
查看次数: |
995367 次 |
最近记录: |