前端面试手撕代码

本文详细解析了前端面试中常见的五个技术点:快速排序、深拷贝、call/apply/bind的区别与实现、new操作的原理以及instanceof的使用。通过实例代码深入理解这些基础概念,助你轻松应对面试挑战。


前言

本篇文章将会列出一些前端面试可能现场手撕的代码,如果你遇到这方面的题目,欢迎评论,我们可以让它更加健全


一、快速排序

function quickSort(arr) {
	if (arr.length <= 1) return arr;	// 只有一个自然是有序的
	let index = Math.floor(arr.length / 2);	// 获取参考值索引,我们要做的就是将比参考值大的都放到右边,否则放在左边
	let value = arr.splice(index, 1);	// 这里用到splice是因为,参考值是不需要遍历的所以把它切走
	let left = [], right = [];
	for (let i=0; i<arr.length; i++) {
		arr[i] < value ? left.push(arr[i]) : right.push(arr[i]);
	}
	return quickSort(left).concat(value, quickSort(right));		// 这里用到递归,懂就算了,不懂就可以这样理解: 总之会一直切下去,知道只剩一个,命中quickSort的if,然后返回
}

二、深拷贝

	function deepClone(target) {
		if (typeof target !== 'object' || target == null) return target;	// 除了数组和对象,都可以直接返回了
		let result = Array.isArray(target) ? [] : {};	// 上述两种情况二选一
		for (let key in target) {
			if (target.hasOwnProperty(key)) {
				result[key] = deepClon(target[key]);	// 又是亲爱的递归
			}
		}
		return result;
	}

三、call apply bind

	// 三个改变this指向的操作
	Function.prototype.call = function() {
		let arr = Array.form(arguments);	// 接收传入的变量
		let context = arr.shift() || windows;	// 第一个为它新的this指向,如果没有就是window
		context.fn = this;					// 这个this指的是 xxx.call 的xxx
		let result = context.fn(...arr);	// 将xxx在新的this执行里面执行一遍
		delete context.fn;					// 删除自己添加的属性
		return result;
	}
	Function.prototype.apply = function() {	// apply和call除了传参形式不一样之外没有区别,就不啰嗦了
		let arr = Array.form(arguments);
		let context = arr[0] || windows;
		let args = arr[1];
		context.fn = this;
		let result = context.fn(...args);
		delete context.fn;
		return result;
	}
	Funciton.prototype.bind = function() {	// bind传值方式和call一样,但是bind返回的是一个改变this指向的函数,并不会自动运行一遍
		let arr = Array.form(arguments);	
		let context = arr.shift() || windows;
		let self = this;	// 将xxx.bind 的xxx用self保存起来,这是因为,在下一个函数里面this就不在,是xxx了,但是self保存后在下一个函数中依然是xxx,很快就看到了
		return function() {
			let args = arr.concat(Array.form(arguments));
			return self.call(context, ...args);			// 很快就在这,我们需要改变的就是xxx的this指向,但是在这里this指的并不是xxx,所以前面用self保存了但是的this(也就是xxx)
		}
	}

四、new 干了什么?

	function myNew (target, ..args) {
		let obj = {};		// 它先创建了一个空对象
		obj.__proto__ = target.prototype;	// 然后让空对象的隐式原型指向了构造函数的prototype;
		target.call(obj, ...args);		// 然后在新创的对象中,执行了一次构造函数
		return obj;
	}

五、instanceof

这里需要对原型和原型链有一定的了解,我这里提供局部的一点来帮助理解一下操作,大神自动忽略

	function _instanceof(L, R) {
		let target = R.prototype;
		L = L.__proto__;
		while(true) {
			if (L === target) return true;
			if (L === null) return false;
			L = L.__proto__;
		}
	}
### 代码面试真题与练习题 在技术面试中,代码是一项重要的考核环节。以下是几类常见的代码题目及其应用场景: #### 1. 数组操作相关 数组作为最基础的数据结构之一,在实际开发中被广泛使用。以下是一些经典的数组操作题目: - 实现 `Array.prototype.map` 方法[^2]。 - 实现 `Array.prototype.filter` 方法[^2]。 - 实现 `Array.prototype.reduce` 方法[^2]。 这些方法的核心在于理解回调函数的作用以及如何遍历数组并返回新的结果。 ```javascript // Array.prototype.map 的实现 Array.prototype.myMap = function(callback, thisArg) { const result = []; for (let i = 0; i < this.length; i++) { result.push(callback.call(thisArg, this[i], i, this)); } return result; }; ``` --- #### 2. 数据结构与算法 这类题目通常涉及栈、队列、链表、二叉树等经典数据结构的操作。例如: - 反转单向链表[^1]。 - 判断字符串是否为回文串[^1]。 - 寻找数组中的最大子序和[^1]。 反转链表是一个典型的例子,它不仅考察了对指针的理解,还考验了逻辑思维能力。 ```javascript function reverseList(head) { let prev = null; let current = head; while (current !== null) { const nextTemp = current.next; current.next = prev; prev = current; current = nextTemp; } return prev; } ``` --- #### 3. 字符串处理 字符串问题是前端工程师常遇到的场景之一,尤其是在输入验证或文本解析方面。常见题目有: - 实现一个简单的模板引擎[^2]。 - 编写一个函数来判断两个字符串是否互为变位词(即字母异位词)[^1]。 下面展示了一个用于检测变位词的简单实现: ```javascript function isAnagram(str1, str2) { if (str1.length !== str2.length) return false; const charCount = {}; for (const char of str1) { charCount[char] = (charCount[char] || 0) + 1; } for (const char of str2) { if (!charCount[char]) return false; charCount[char]--; } return true; } ``` --- #### 4. 类型判断与继承机制 对于 JavaScript 开发者来说,掌握类型判断和原型链是非常必要的。典型的代码题目包括: - 自定义实现 `instanceof` 运算符。 - 使用 ES6 Class 构建对象模型,并模拟多重继承[^1]。 下面是自定义 `instanceof` 的一种可能解法: ```javascript function myInstanceof(left, right) { let proto = Object.getPrototypeOf(left); const prototype = right.prototype; while (proto !== null) { if (proto === prototype) return true; proto = Object.getPrototypeOf(proto); } return false; } ``` --- #### 5. 并发控制与性能优化 随着现代应用复杂度增加,了解并发编程变得尤为重要。一些热门题目如下: - 设计一个限流器(Rate Limiter),限制 API 调用频率。 - 实现防抖(Debounce)和节流(Throttle)功能。 这里提供了一种基于时间戳的防抖函数实现方式: ```javascript function debounce(func, wait) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), wait); }; } ``` --- ### 总结 以上列举了几种类别的代码题目,涵盖了数组操作、数据结构与算法、字符串处理等多个领域。通过不断练习这些题目,可以有效提升编码能力和应对面试的信心。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值