skip to content
天真笔录

一些手写题

/ 4 min read

深拷贝

原生版

const obj = {
	name: "tianzhen",
};
const newObj = JSON.parse(JSON.stringify(obj));
newObj.age = 18;
console.log("==================", newObj);
console.log("==================", obj);

改变newObj不会影响到obj

  • JSON.stringify存在的问题
const obj = {
	a: undefined,
	b: null,
	c: "tianzhen",
	d: function () {},
	e: [1, 2, 3],
	f: Symbol("1"),
	[Symbol("1")]: "symbol",
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log("newObj==================", newObj);
// {
//     "b": null,
//     "c": "tianzhen",
//     "e": [
//         1,
//         2,
//         3
//     ]
// }
  • undefined, 函数, Symbol作为属性值的时候会直接忽略,Symbol作为key也会忽略
  • Date对象会变成字符串
  • RegExp对象会变成空对象{}
  • 存在循环引用会报错

基础版

const obj = {
	name: "tianzhen",
	getName: function () {
		console.log(this.name);
	},
	friends: ["lisi", "wangwu"],
};
function deepCopy(originObj) {
	if (typeof originObj !== "object" && !originObj) {
		return;
	}
	const target = Array.isArray(originObj) ? [] : {};
	for (let key in originObj) {
		if (Object.hasOwnProperty.call(originObj, key)) {
			target[key] = typeof originObj[key] === "object" ? deepCopy(originObj[key]) : originObj[key];
		}
	}
	return target;
}

升级版

主要是解决循环引用

const obj = {
	name: "tianzhen",
	age: undefined,
	getName: function () {
		console.log(this.name);
	},
	friends: ["lisi", "wangwu"],
};
obj.info = obj; // 添加循环引用

function deepCopy(originObj, map = new WeakMap()) {
	if (typeof originObj !== "object" && !originObj) {
		return;
	}
	if (map.has(originObj)) {
		return map.get(originObj);
	}
	const target = Array.isArray(originObj) ? [] : {};
	map.set(originObj, target);

	for (let key in originObj) {
		if (Object.hasOwnProperty.call(originObj, key)) {
			target[key] =
				typeof originObj[key] === "object" ? deepCopy(originObj[key], map) : originObj[key];
		}
	}
	return target;
}

再升级

function getType(obj) {
	const type = Object.prototype.toString.call(obj).slice(8, -1);
	return type;
}

function deepCopy(originObj, map = new WeakMap()) {
	if (getType(originObj) === "RegExp") {
		return new RegExp(originObj);
	}

	if (getType(originObj) === "Date") {
		return new Date(originObj);
	}

	if (typeof originObj === "symbol") {
		return Symbol(originObj.description);
	}

	if (typeof originObj !== "object" || originObj === null) {
		return originObj;
	}

	if (map.has(originObj)) {
		return map.get(originObj);
	}

	let target = Array.isArray(originObj) ? [] : {};
	map.set(originObj, target);

	for (const key in originObj) {
		target[key] = deepCopy(originObj[key], map);
	}
	return target;
}

柯里化

  • 只传给函数一部分参数来调用它,返回一个函数再处理剩余参数
  • 这个过程就称为柯里化
// 实现一
function add(x, y, z) {
	return x + y + z;
}
add(1, 2, 3);
add(1)(2)(3); // 实现类似这种调用

function currying(fn) {
	function curried(...args) {
		if (args.length >= fn.length) {
			return fn.apply(this, args);
		} else {
			// 参数不足时需要返回一个函数
			return function (...args2) {
				return curried.apply(this, [...args, ...args2]);
			};
		}
	}
	return curried;
}
// 实现二
function currying(fn, ...args) {
	return fn.length <= args.length ? fn.apply(this, args) : currying.bind(this, fn, ...args);
}

数组扁平化(拍平)

// 实现一
let arr = [1, [2, [3, 4, 5]]];
function flatten(arr) {
	let result = [];
	arr.forEach((item) => {
		if (Array.isArray(item)) {
			result = result.concat(flatten(item)); // 递归
		} else {
			result.push(item);
		}
	});
	return result;
}
// 实现二(reduce)
let arr = [1, [2, [3, 4, 5]]];
function flatten(arr) {
	return arr.reduce((prev, next) => {
		prev.concat(Array.isArray(next) ? flatten(next) : next);
	}, []);
}

数组乱序

// 方法一
const arr = [1, 2, 3, 4, 5, 6];
arr.sort(() => {
	return Math.random() - 0.5;
});
// 方法二
const arr = [1, 2, 3, 4, 5, 6];
let len = arr.length;
while (len !== 0) {
	const randomIndex = parseInt(Math.random() * len);
	len--;
	[arr[len], arr[randomIndex]] = [arr[randomIndex], arr[len]];
}

arrayToTree

url parse