第 162 题:实现对象的 Map 函数类似 Array.prototype.map
NieZhuZhu opened this issue · 39 comments
列如:
// 实现一个 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}
参考:
列如:
// 实现一个 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(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);
})();
列如:
// 实现一个 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 (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
返回但是做个判断总是好的
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}
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)
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);
为什么怎么多人搞深克隆🙄
参考自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);
Object.prototype.map = function(handleFn){
return Object.keys(this).reduce((newObj, key) => {
return newObj[key] = handleFn(this[key], key, this);
}, {})
}
function objMap(source, cb) {
return Object.keys(source).reduce((pre, key) => {
pre[key] = cb(key, source[key], source);
return pre;
}, {});
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
}
})
Object.prototype.map = function (iteratee) {
const result = {}
for (const key of Object.keys(source)) {
result[key] = iteratee.call(this, source[key], key)
}
return result
}
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;
})
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));
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);
})
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}
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
转字符串再转对象,性能不好
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;
}, {});
}
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
/**
*
* @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;
};
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)
})
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;
}
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}
分析实现的效果
Array的map语法如下
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
结论
map
的入参为回调函数,需要做函数类型判断map
的返回值为一个经过回调函数处理后的对象- 回调函数的入参分别是:
value
、index
、原始数据 - 回调函数的返回值会作为最终对象的
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))
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;
}
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;
}));
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 }
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);
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;
};
}
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;
});
**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;
};**
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);
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
// }
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)
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;
};
Array.prototype.map2 = function(callback) {
let arr = [];
for (let i = 0; i < this.length; i++) {
arr.push(callback(this[i], i));
}
return arr;
};
/**
* 使用给定的函数对对象的值进行映射,并返回一个包含映射值的新对象。
*
* @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';
}
))
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)
// 实现对象的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 }
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;
}