我有一个目标:

myObject = { 'a': 1, 'b': 2, 'c': 3 }

我正在寻找一个本地方法,类似于Array.prototype.map,可按如下方式使用:

newObject = myObject.map(function (value, label) {
    return value * value;
});

// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

JavaScript是否有这样的对象映射函数?(我希望Node.JS使用这个,所以我不关心跨浏览器问题。)


当前回答

使用以下映射函数定义myObject.map

o => f=> Object.keys(o).reduce((a,c)=> c=='map' ? a : (a[c]=f(o[c],c),a), {})

让map=o=>f=>Object.keys(o).reduce((a,c)=>c=='map'?a:(a[c]=f(o[c],c),a),{})//测试初始化myObject={“a”:1,“b”:2,“c”:3}myObject.map=map(myObject);//你可以这样做,但不建议这样做//(您将看到“map”键任意/所有对象)//Object.prototype.map=map(myObject);//所述OP所需接口newObject=myObject.map(函数(值,标签){返回值*值;});console.log(newObject);

其他回答

编辑:使用较新JavaScript功能的规范方法是-

const identity = x =>
  x

const omap = (f = identity, o = {}) =>
  Object.fromEntries(
    Object.entries(o).map(([ k, v ]) =>
      [ k, f(v) ]
    )
  )

其中o是某个对象,f是映射函数。或者我们可以说,给定一个a->b的函数和一个值为a的对象,生成一个值类型为b的对象。作为伪类型签名-

// omap : (a -> b, { a }) -> { b }

最初的答案是为了演示一个强大的组合子mapReduce,它允许我们以不同的方式思考我们的转换

m、 映射函数–让您有机会在…r、 reduce函数–此函数将累加器与映射元素的结果组合

直观地说,mapReduce创建了一个新的reduce,我们可以直接插入Array.prototype.reduce中。但更重要的是,我们可以通过使用对象幺半群、object.assign和{}来简单地实现我们的对象函子实现omap。

常量标识=x=>x(x)常量mapReduce=(m,r)=>(a,x)=>r(a,m(x))常量omap=(f=身份,o={})=>对象.键(o)减少(mapReduce(k=>({[k]:f(o[k])}),对象分配), {})常量平方=x=>x×x常量数据={a:1,b:2,c:3}console.log(omap(方形,数据))//{a:1,b:4,c:9}

请注意,我们实际需要编写的程序的唯一部分是映射实现本身——

k => ({ [k]: f (o[k]) })

也就是说,给定已知对象o和某个键k,构造一个对象,其计算属性k是对键的值o[k]调用f的结果。

如果我们首先抽象oreduce,我们就可以一窥mapReduce的测序潜力

// 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
    )

一切都是一样的,但现在可以在更高级别上定义omap。当然,新的Object.entries让这看起来很愚蠢,但练习对学习者来说仍然很重要。

你不会在这里看到mapReduce的全部潜力,但我分享这个答案,因为看到它可以应用到多少地方很有趣。如果您对它的派生方式和其他有用的方式感兴趣,请查看此答案。

const mapObject = (targetObject, callbackFn) => {
    if (!targetObject) return targetObject;
    if (Array.isArray(targetObject)){
        return targetObject.map((v)=>mapObject(v, callbackFn))
    }
    return Object.entries(targetObject).reduce((acc,[key, value]) => {
        const res = callbackFn(key, value);
        if (!Array.isArray(res) && typeof res ==='object'){
            return {...acc, [key]: mapObject(res, callbackFn)}
        }
        if (Array.isArray(res)){
            return {...acc, [key]: res.map((v)=>mapObject(v, callbackFn))}
        }
        return {...acc, [key]: res};
    },{})
};
const mapped = mapObject(a,(key,value)=> {
    if (!Array.isArray(value) && key === 'a') return ;
    if (!Array.isArray(value) && key === 'e') return [];
    if (!Array.isArray(value) && key === 'g') return value * value;
    return value;
});
console.log(JSON.stringify(mapped)); 
// {"b":2,"c":[{"d":2,"e":[],"f":[{"g":4}]}]}

此函数递归地遍历对象和对象数组。如果返回未定义,则可以删除属性

我的回答主要基于这里的最高评分,希望每个人都能理解(在我的GitHub上也有同样的解释)。这就是为什么他对地图的实施有效:

Object.keys(images).map((key) => images[key] = 'url(' + '"' + images[key] + '"' +    
')');

该函数的目的是获取一个对象,并使用对所有对象(对象和数组都一样)可用的方法修改对象的原始内容,而不返回数组。JS中的几乎所有东西都是一个对象,因此,继承管道下游的元素在技术上可能会使用上游元素可用的对象(反之亦然)。

这之所以有效,是因为.map函数返回了一个数组REQUIRING,您可以提供一个数组的显式或隐式RETURN,而不是简单地修改现有对象。你本质上通过使用object.keys来欺骗程序,使其认为对象是一个数组,这将允许你使用map函数,并将其作用于各个键关联的值(我实际上意外返回了数组,但已修复)。只要没有正常意义上的返回,就不会创建原始对象仍然完整并按程序修改的数组。

这个特定的程序获取一个名为images的对象,并获取其键的值,并附加url标记以供在另一个函数中使用。原文如下:

var images = { 
snow: 'https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305', 
sunny: 'http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-east-   
Matanzas-city- Cuba-20170131-1080.jpg', 
rain: 'https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg' };

…并修改为:

var images = { 
snow: url('https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305'),     
sunny: url('http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-   
east-Matanzas-city- Cuba-20170131-1080.jpg'), 
rain: url('https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg') 
};

对象的原始结构保持不变,只要没有返回,就可以正常访问属性。不要让它像正常一样返回数组,一切都会好起来。目标是将原始值(图像[key])重新设计为所需的值,而不是其他值。据我所知,为了防止数组输出,必须有图像的重新分配[key],并且没有返回数组的隐式或显式请求(变量赋值完成了这一点,并且对我来说来回出现问题)。

编辑:

要解决他关于创建新对象的另一个方法,以避免修改原始对象(为了避免意外创建数组作为输出,似乎仍然需要重新分配)。这些函数使用箭头语法,如果您只是想创建一个新对象以供将来使用,则可以使用。

const mapper = (obj, mapFn) => Object.keys(obj).reduce((result, key) => {
                result[key] = mapFn(obj)[key];
                return result;
            }, {});

var newImages = mapper(images, (value) => value);

这些功能的工作方式如下:

mapFn接受稍后要添加的函数(在这种情况下(value)=>value),并简单地返回存储在那里的任何内容,

然后在result[key]=mapFn(obj)[key]中重新定义与键关联的原始值

并返回对结果执行的操作(位于括号中的累加器在reduce函数结束时启动)。

所有这些都是在所选对象上执行的,但仍然不能对返回的数组进行隐式请求,只有在我所知的重新分配值时才有效。这需要一些心理体操,但减少了所需的代码行,如上文所示。输出完全相同,如下所示:

{snow: "https://www.trbimg.com/img-5aa059f5/turbine/bs-   
md-weather-20180305", sunny: "http://www.cubaweather.org/images/weather-
photos/l…morning-east-Matanzas-city-Cuba-20170131-1080.jpg", rain: 
"https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg"}

请记住,这适用于非数字。通过在mapFN函数中简单地返回值,可以复制任何对象。

为了获得最佳性能。

如果您的对象不经常更改,但需要经常迭代,我建议使用本地映射作为缓存。

//示例对象var obj={a:1,b:2,c:'something'};//缓存映射var objMap=新映射(Object.entries(obj));//Map对象上的快速迭代objMap.forEach((项,键)=>{//用一件物品做点什么console.log(键,项);});

Object.entries已经在Chrome、Edge、Firefox和beta Opera中运行,因此它是一个经得起未来考验的功能。这是ES7的,所以用塑料填充https://github.com/es-shims/Object.entries对于IE,它不起作用。

另一种不同的做法是使用自定义的json字符串函数,该函数也可以处理深层对象。如果您打算将其作为json发布到服务器,这可能很有用

常量obj={‘a’:1,‘b’:2,x:{‘c’:3}}const json=json.stringify(obj,(k,v)=>typeof v==“number”?v*v:v)console.log(json)console.log('返回json:',json.parse(json))