Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 162 题:实现对象的 Map 函数类似 Array.prototype.map #431

Open
NieZhuZhu opened this issue Nov 1, 2020 · 39 comments
Open

Comments

@NieZhuZhu
Copy link

列如:

// 实现一个 map 函数
const targetData = {
  a: 2,
  b: 3,
  c: 4,
  d: 5
};
const objMap = (obj, fn) => {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  return JSON.parse(JSON.stringify(obj, fn));
};
objMap(targetData, (key, value) => {
  if (value % 2 === 0) {
    return value / 2;
  }
  return value;
});
// {a: 1, b: 3, c: 2, d: 5}

参考:

你不知道的 JSON.stringify() 的威力

@Mrcxt
Copy link

Mrcxt commented Nov 3, 2020

列如:

// 实现一个 map 函数
const targetData = {
  a: 2,
  b: 3,
  c: 4,
  d: 5
};
const objMap = (obj, fn) => {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  return JSON.parse(JSON.stringify(obj, fn));
};
objMap(targetData, (key, value) => {
  if (value % 2 === 0) {
    return value / 2;
  }
  return value;
});
// {a: 1, b: 3, c: 2, d: 5}

参考:

你不知道的 JSON.stringify() 的威力

这个实现有问题,首先JSON.stringify(obj, fn)中第一次传入fn中的参数为 ""和对象本身,从第二次开始才会传入key和val,所以应该加上条件处理。

(() => {

    Object.prototype._map = function (fn, oThis = null) {
        if (typeof fn !== 'function') {
            throw new TypeError(`${fn} is not a function !`)
        }
        return JSON.parse(JSON.stringify(this, (key, val) => {
            if (key) {
                return fn.call(oThis, key, val, this)
            } else {
                return val
            }
        }))
    }
    // 用例
    let obj = {
        a: 2,
        b: 3,
        c: 4,
        d: 5
    };
    let _obj = obj._map((key, val, o) => {
        return ++val
    })
    console.log(_obj);
})();

@NieZhuZhu
Copy link
Author

列如:

// 实现一个 map 函数
const targetData = {
  a: 2,
  b: 3,
  c: 4,
  d: 5
};
const objMap = (obj, fn) => {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  return JSON.parse(JSON.stringify(obj, fn));
};
objMap(targetData, (key, value) => {
  if (value % 2 === 0) {
    return value / 2;
  }
  return value;
});
// {a: 1, b: 3, c: 2, d: 5}

参考:
你不知道的 JSON.stringify () 的威力

这个实现有问题,首先 JSON.stringify (obj, fn) 中第一次传入 fn 中的参数为 "" 和对象本身,从第二次开始才会传入 key 和 val,所以应该加上条件处理。

(() => {

    Object.prototype._map = function (fn) {
        if (typeof fn !== 'function') {
            throw new TypeError(`${fn} is not a function !`)
        }
        return JSON.parse(JSON.stringify(this, (key, val) => {
            if (key) {
                return fn.call(this, key, val)
            } else {
                return val
            }
        }))
    }
    // 用例
    let obj = {
        a: 2,
        b: 3,
        c: 4,
        d: 5
    };
    let _obj = obj._map((key, val) => {
        return ++val
    })
    console.log(_obj);
})();

对的,虽然不会被 JSON.stringify 返回但是做个判断总是好的

@Cecilxx
Copy link

Cecilxx commented Nov 9, 2020

Object.prototype.map= function(cb) {
    const obj = this
    const result = {}
    for(key in obj) {
        if (obj.hasOwnProperty(key)) {
            const item = cb(key, obj[key])
            result[key] = item
        }
    }
    return result
}
const test1 = {
  a: 2,
  b: 3,
  c: 4,
  d: 5
};
const r1 = test1.map(() => {
   if (value % 2 === 0) {
    return value / 2;
  }
  return value;
})
// r1 :  {a: 1, b: 3, c: 2, d: 5}

const test2 = {
 a: 2,
 b: 3,
 c: 4,
 d: 5
};
const r2 = test2.map((key, val) => {
  return ++val
})
// r2: {a: 3, b: 4, c: 5, d: 6}

@FatDoge
Copy link

FatDoge commented Nov 10, 2020

const targetData = {
  a: 2,
  b: 3,
  c: 4,
  d: 5
};

Object.prototype.map = function(fn) {
  const res = {}
  for(e in this) {
    if(this.hasOwnProperty(e)) {
      res[e] = fn(this[e])
    }
  }
  return res
}

const p = targetData.map(e => e + 1)
console.log(p)

@hcc0007
Copy link

hcc0007 commented Nov 10, 2020

Object.prototype.map = function(fn) {
  const deepclone = JSON.parse(JSON.stringify(this));
	return Object.keys(deepclone).reduce((result, key, index) => {
  	result[key] = fn(deepclone[key], key, index);
    return result;
  }, {})
}

const obj = {
	a: 1,
  b: 2,
  c: 3,
}
const newObj = obj.map((value, key, index) => ({ [key]: value + ',,,' }));
console.log(newObj);

@JianJroh
Copy link

为什么怎么多人搞深克隆🙄

参考自JavaScript Array map() 定义与用法 https://www.runoob.com/jsref/jsref-map.html

Object.prototype.map = function (handleFn,thisValue) {
    const obj = this;
    let res = {};
    for (let prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            res[prop] = handleFn.call(thisValue,obj[prop], prop,obj);
        }
    }
    return res;
};
// 测试用例
var obj = {
    name: 'sunny',
    sex: 'man'
};
var res = obj.map(function(val, prop,obj){
    console.log(this);
    console.log(val, prop,obj);
    return prop + '--' + val;
}, {name: 'thisthis'});
console.log('res:',res);

@getOnce
Copy link

getOnce commented Nov 24, 2020

Object.prototype.map = function(handleFn){
return Object.keys(this).reduce((newObj, key) => {
return newObj[key] = handleFn(this[key], key, this);
}, {})
}

@linrunzheng
Copy link

function objMap(source, cb) {
  return Object.keys(source).reduce((pre, key) => {
    pre[key] = cb(key, source[key], source);
    return pre;
  }, {});

@blank1u
Copy link

blank1u commented Dec 13, 2020

Object.prototype.map = function (fn) {
    let result = {}
    for (const key in this) {
        if (this.hasOwnProperty(key)) {
            const element = this[key]
            result = fn.call(this, key, element)
        }
    }
    return result
}


let res = obj.map((key, val) => {
    return {
        key, val
    }
})

@zfowed
Copy link

zfowed commented Jan 25, 2021

Object.prototype.map = function (iteratee) {
  const result = {}
  for (const key of Object.keys(source)) {
    result[key] = iteratee.call(this, source[key], key)
  }
  return result
}

@Jialufeng
Copy link

Jialufeng commented Mar 24, 2021

class MyArr {
    constructor(arr) {
        this.arr = arr;
    }
    map(cb) {
        let newArr = [];
        for(var i =0 ; i < this.arr.length; i++) {
           newArr[i] = cb(this.arr[i]);
        }
        return newArr;
    }
}
let arr = new MyArr([1,2,3,4,5])
arr.map((item) => {
    retrun item +1;
})

@moonyoulove
Copy link

const map = Symbol("map");
Object.prototype[map] = function (callback) {
  const obj = {};
  for (let key in this) {
    obj[key] = callback(this[key], key, this);
  }
  return obj;
};
console.log({ a: 1, b: 2, c: 3 }[map](v => v + 1));

@Z1hgq
Copy link

Z1hgq commented Mar 31, 2021

Object.prototype.map = function(callbackfn) {
    Object.keys(this).map((value, index, array) => {
        callbackfn(this[value], value, this);
    });
}

const obj = new Object({
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: 5
});
obj.map((value, index, array) => {
    console.log(value, index, array);
})

@MrLeihe
Copy link

MrLeihe commented Apr 14, 2021

Object.prototype._map = function (fn) {
  const obj = this
  let result = {}
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      var res = fn(obj[key], key, obj)
      result[key] = res
    }
  }
  return result
}
var o = { a: 1, b: 2 }
o._map((value, key, source) => {
  return 1
})
// {a: 1, b: 1}

@zzz1220
Copy link

zzz1220 commented Apr 16, 2021

function objMap(obj,func) {
    if(typeof func  !== 'function') {
        throw new Error(`${func} must be a function`)
    }
    const ctor = obj.__proto__.constructor
    let res = new ctor();
    for(let prop of Object.getOwnPropertyNames(obj)) {
        res[prop] = func(obj[prop])
    }
    return res
}

function Person(a,b,c,d) {
    this.a = a
    this.b = b
    this.c = c
    this.d = d
}

Person.prototype.e = 'prototype value'

let origin  = new Person(1,2,3,4)
let dst = objMap(origin,(a)=>a*a)
console.log(origin,dst)
// Person { a: 1, b: 4, c: 9, d: 16 }
console.log(origin.__proto__ === dst.__proto__) // true
console.log(dst instanceof Person) // true
console.log(dst.e) // prototype value

@satrong
Copy link

satrong commented Apr 23, 2021

转字符串再转对象,性能不好

@nomyfan
Copy link

nomyfan commented May 8, 2021

function objectMap(obj, fn) {
  // Not check type yet
  //
  return Object.entries(obj)
    .map(([key, value]) => [key, fn(key, value)])
    .reduce((acc, [key, value]) => {
      acc[key] = value;
      return acc;
    }, {});
}

@jumplee
Copy link

jumplee commented May 12, 2021

function map(fn,scope){
   var result=[];
var i=0;
   var realScope=scope || this
   var len=this.length;
  while(i<len){
result[i]=fn.call(realScope,this[i],i)
i++;
}

return result;
}
Array.prototype.map=map

@peterczg
Copy link

/**
 *
 * @param {Function} callbackFn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the object.
 * @param {Record<string, any>} thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
 * @returns {Record<string, any>}
 */
Object.prototype.map = function (callbackFn, thisArg) {
  if (typeof callbackFn !== "function") {
    throw new TypeError(`${callbackFn} is not a function`);
  }
  const ret = {};
  const hasOwn = Object.prototype.hasOwnProperty;
  for (let key in this) {
    hasOwn.call(this, key) &&
      (ret[key] = callbackFn.call(thisArg, this[key], key, this));
  }
  return ret;
};

@Y-J-H
Copy link

Y-J-H commented May 19, 2021

var testObj = {
  a: 1,
  b: 2,
  c: { d: 1 }
}
Object.prototype.map = function (callbackfn) {
  for (var [key, val] of Object.entries(this)) {
    callbackfn(key, val)
  }
}

testObj.map((key, val) => {
  console.log(key, val)
})

@sytclh
Copy link

sytclh commented Jun 3, 2021

Object.prototype.map = function(callbackFn, thisArg) {
    if (typeof callbackFn !== "function")
       throw new TypeError(`${callbackFn} is not a function`);
    if (Object.prototype.toString.call(thisArg) != "[object Object]")
        thisArg = this;
    for (let key in thisArg) {
        if (thisArg.hasOwnProperty(key)) {
            thisArg[key] = callbackFn(thisArg[key], key, thisArg);
        }
    }
    return thisArg;
}

@shengdan19
Copy link

var obj = { a: 1 }
function objMap(fn) {
var obj1 = {};
Object.keys(this).forEach((i) => {
obj1[i] = fn(this[i])
});
return obj1
}
Object.prototype.map = objMap;
console.log(obj.map((i) => i + 1), obj) // {a:2} {a:1}

@NikaSSL
Copy link

NikaSSL commented Jun 26, 2021

分析实现的效果

Array的map语法如下

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])

结论

  • map的入参为回调函数,需要做函数类型判断
  • map的返回值为一个经过回调函数处理后的对象
  • 回调函数的入参分别是:valueindex、原始数据
  • 回调函数的返回值会作为最终对象的value值,若无返回则为undefined

Object.prototype.map实现

// 实现对象的 Map 函数类似 Array.prototype.map
Object.prototype.map = function (fn) {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function`);
  }
  const result = {}
  for (const [key, value] of Object.entries(this)) {
    result[key] = fn(value, key, this)
  }
  return result
}

function _isEqual(obj1, obj2) {
  // 基于测试数据是简单的数据
  // 采用JSON.stringify()进行一致性判别
  return JSON.stringify(obj1) === JSON.stringify(obj2)
}

const testObj = {
  name: 'Nika',
  age: 18
}

// map处理后的返回
const mapRes = testObj.map((value, key, originObj) => {
  if (key === 'name') {
    return `My name is ${value}`
  }
})

// map后的目标结果
const target = {
  name: `My name is ${testObj.name}`,
  age: undefined
}

console.assert(_isEqual(mapRes, target))

@poppydani
Copy link

Array.prototype._map = function (fn) {
  const arr = this;
  const res = [];
  for (let i = 0; i < arr.length; i++) {
    const ele = arr[i];
    res[i] = fn.call(globalThis, ele, i, arr);
  }
  return res;
}

@CatsAndMice
Copy link

Object.prototype.map = function (fn, _self) {
    let keys = Object.keys(this),
        values = [];
    for (let i = 0; i < keys.length; i++) {
        values.push(fn.call(_self, this[keys[i]], i))
    }
    return values;
}

let obj = {
    key: 'lihai',
    value: "map"
}

console.log(obj.map((val, index) => {
    console.log(val, index);
    return val;
}));

@shaun2099
Copy link

shaun2099 commented Sep 20, 2021

Object.prototype.map = function(fn) {
  let new_obj = {}
  for (const p in this) {
    if (this.hasOwnProperty(p)) {
      console.log(`${p} = ${this[p]}`)
      new_obj[p] = fn(this[p])
    }
  }
  return new_obj
}
let obj = {
  x: 1,
  y: 2
}

const obj2 = obj.map(x => x * 2)
console.log(obj2)
//output : { x: 2, y: 4 }

@beilo
Copy link

beilo commented Dec 1, 2021

    Object.prototype.map = function (fn) {
        const res = {};
        for (const key in this) {
            // 不加这句会把map添加进去
            if (Object.hasOwnProperty.call(this, key)) {
                const value = this[key];
                res[key] = fn(value, key, this);
            }
        }
        return res;
    };

    const testObj = {
        name: "Nika",
        age: 18,
    };

    const mapObj = testObj.map((value, key) => {
        if (key === "name") {
            return `My name is ${value}`;
        }
    });

    console.log(testObj);
    console.log(mapObj);

@antyoxydant
Copy link

MDN的map polyfill

// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: https://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {

  Array.prototype.map = function(callback/*, thisArg*/) {

    var T, A, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    // 1. Let O be the result of calling ToObject passing the |this|
    //    value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal
    //    method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: https://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (arguments.length > 1) {
      T = arguments[1];
    }

    // 6. Let A be a new array created as if by the expression new Array(len)
    //    where Array is the standard built-in constructor with that name and
    //    len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while (k < len) {

      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal
      //    method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        //    method of O with argument Pk.
        kValue = O[k];

        // ii. Let mappedValue be the result of calling the Call internal
        //     method of callback with T as the this value and argument
        //     list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // For best browser support, use the following:
        A[k] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };
}

@LiuSandy
Copy link

const targetData = {
  a: 2,
  b: 3,
  c: 4,
  d: 5,
};
Object.prototype.objMap = function (fn) {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  return JSON.parse(
    JSON.stringify(this, (key, value) => {
      if (!key) {
        return value;
      }
      return fn.call(null, key, value);
    })
  );
};

const newData = targetData.objMap((key, value) => {
  if (value % 2 === 0) {
    return value / 2;
  }
  return value;
});

@Verahuan
Copy link

Verahuan commented Mar 10, 2022

**const objectMap = (obj, operation) => {
  if (typeof operation !== "function") {
    throw new TypeError(`${operation} is not a function !`);
  }

  const res = Object.fromEntries(
    Object.entries(obj).map(([key, val]) => [key, operation(val)])
  );
  return res;
};**

@itLeeyw
Copy link

itLeeyw commented May 19, 2022

Array.prototype.map = function (callback, thisArg) {
  if (!this) throw TypeError('this 未定义或者为 null');
  const bindThis = thisArg ?? null;
  
  const arrObj = Object(this);
  const len = arrObj.length >>> 0;
  
  let newArr = [];
  let idx = 0;
  while(idx < len) {
    const item = arrObj[idx];
    if (idx in arrObj) {
      const res = callback.call(bindThis, item, idx, arrObj);
      newArr[idx] = res;
    }
    idx++;
  }
  
  return newArr;
}

const a = [1, 4, 9, 16];

const a1 = a.map(x => x * 2);
console.log(a1);

@lucaslmlok
Copy link

Object.prototype.map = function (callbackFn) {
  if (typeof callbackFn === 'undefined') {
    throw new TypeError(`${callbackFn} is not a function`);
  }
  const res = {};
  Object.entries(this).forEach(([key, value]) => {
    res[key] = callbackFn(value, key);
  });
  return res;
};

const obj = {
  a: 1,
  b: 100,
  c: 'human',
  d: 'earth',
  e: true,
};

const transformedObj = obj.map((value, key) => {
  if (typeof value === 'number') return value + 2;
  if (typeof value === 'string') return `${value} is awesome`;
  if (typeof value === 'boolean') return !value;
  return value;
});

console.log(transformedObj);
// {
//   a: 3,
//   b: 102,
//   c: 'human is awesome',
//   d: 'earth is awesome',
//   e: false
// }

@code-small-white
Copy link

const a={a:1,b:2,c:3}
const objMap = (obj, cb) => {
    Object.entries(obj).map(([key, val]) => cb(val, key, obj))
}
objMap(a,console.log)

@smile0125
Copy link

smile0125 commented Dec 13, 2022

Array.prototype.myMap = function (cb) {
  const _arr = this;
  const _arg2 = arguments[1] || window;
  const _length = _arr.length;
  let res = [];

  for (let i = 0; i < _length; i++) {
    res.push(cb.apply(_arg2, [_arr[i], i, _arr]));
 }
  return res;
};

请看map,forEach, filter,some,every, reduce,reduceRight方法实现

@xiaoguoaa
Copy link

Array.prototype.map2 = function(callback) {
  let arr = [];
  for (let i = 0; i < this.length; i++) {
    arr.push(callback(this[i], i));
  }
  return arr;
};

@2113ic
Copy link

2113ic commented Apr 12, 2023

/**
 * 使用给定的函数对对象的值进行映射,并返回一个包含映射值的新对象。
 *
 * @param {Object} obj - 要映射的对象。
 * @param {Function} fn - 用于映射值的函数。
 * @returns {Object} - 包含映射值的新对象。
 */
function objectMap(obj, fn) {
  const stored = {};

  Object.keys(obj).forEach((item) => {
    const value = obj[item];

    stored[item] = fn(value);
  });

  return stored;
}

// Test
console.log(
objectMap(
  {
    name: "xiaoyan",
    age: 23,
    kills: ["html", "css", "javascript"],
    action: {
      eat: () => {},
    },
  },
  (item) => {
    if (typeof item === "number") return item * 2;
    if (typeof item === "string") return item + '-hello';
  }
))

@GraceLiu647
Copy link

Object.prototype.myMap = function (callback) {
const entries = Object.entries(this)
return entries.map((entry) => {
let [key, value] = entry
value = callback(value, key)
return [key, value]
})
}

const obj = {
a: 1,
b: 2,
c: 3
}
const result = obj.myMap((item, key) => {
return key + item
})
console.log(result)

@chen-ziwen
Copy link

// 实现对象的map
Object.prototype.map = function (callback) {
    if (typeof callback !== 'function') {
        throw new TypeError(`${callback} is not a function!`)
    }
    return JSON.parse(JSON.stringify(this, (key, value) => {
        if (key) {
            return callback.call(this, value, key, this);
        } else {
            return value;
        }
    }))
}

const targetData = {
    a: 2,
    b: 3,
    c: 4,
    d: 5
};
const t = targetData.map((item) => item * 2);

console.log(t); // { a: 4, b: 6, c: 8, d: 10 }

@chens01
Copy link

chens01 commented Aug 9, 2024

function objMap(obj, fn) {
  if (typeof fn != 'function') {
    throw new Error('fn must be a function');
  }

  const res = {};
  if(obj.__proto__ instanceof Object) {
    res.__proto__ = obj.__proto__;
  }
  Object.getOwnPropertyNames(obj).forEach((key) => {
    res[key] = fn(obj[key], key);
  });

  return res;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests