js常见手撕代码

实现一个简单的闭包

// 实现隔一秒输出一个数字,数字递增
// 1.利用匿名自执行函数创建闭包实现
for(var i = 0; i < 5; i++){
	(function(arg){
        setTimeout(function run(){
            console.log(arg)
        }, arg*1000)
	})(i)
}
// 2.使用 let 实现
for(let i = 0; i < 5; i++){
	setTimeout(()=>{
        console.log(i)
    },i*1000)
}

节流和防抖

// 节流函数(在规定的时间间隔内只触发一次事件处理函数,如果多次触发,则什么也不做)
function throttle(func, wait){
	let start = Date.now()
	return function(){
		let end = Date.now()
		if(end - start > wait){
			return func.apply(this, arguments)
			start = end
		}
	}
}
// 防抖函数(在规定的时间间隔内只触发一次事件处理函数,如果多次触发则重新设置计时器,即把在规定时间内多次触发的事件合并为一次)
function debounce(func, wait){
	let timer = null
	return function() {
		if(timer !== null){
			clearTimeout(timer)
			timer = null
		}
		timer = setTimeout(() => {
			func.apply(this, arguments)
		}, wait)
	}
}

实现 sleep 函数

// 1.使用 for 循环实现
function sleep(func, wait) {
	let start = Date.now()
	while(Date.now() - start < wait){}
	func()
}
// 2.setTimeout
function sleep(func, wait) {
	setTimeout(func, wait)
}
// 3.promise
function sleep(func, wait) {
	new Promise((resolve) => {
		setTimeout(resolve, wait)
	}).then(value => {
		func()
	})
}
// 4.async
async function sleep(func, wait) {
	await new Promise((resolve) => {
		setTimeout(resolve, wait)
	})
	func()
}

实现 bind、apply、call

// bind
Function.prototype.bind = function(context){
	let args = [].slice.call(arguments, 1)
	let that = this
	function f(){
		return that.apply(this instanceof f ? this : context, args.concat([].slice.call()))
	}
	f.prototype = Object.create(this.prototype)
	return f;
}
// apply
Function.prototype.apply(context, arg) {
	if(typeof this !== 'function') {
		throw new Error('类型错误')
	}
	context = context || window
	context.func = this
	let result = context.func(...arg)
	delete context.func
	return result
}
// call
Function.prototype.call(context, ...arg) {
	if(typeof this !== 'function') {
		throw new Error('类型错误')
	}
	context = context || window
	context.func = this
	let result = context.func(...arg)
	delete context.func
	return result
}

手写 new

function new (Func, ...arg){
	let obj = {}
	obj.__proto__ = Func.prototype
	let res = Func.call(obj, ...arg)
	return res instanceof Object ? res : obj
}

实现 instanceof

// instanceof 是通过原型链判断的,即判断构造函数的原型对象是否在 obj 的原型链上
function InstanceOf(obj, Fun){
	let left = onj.__proto__
	let right = Fun.prototype
	while(1){
		if(left === null) {
			return false
		}
		if(left === right){
			return true
		}
		left = left.__proto__
	}
}

使用 Promise 封装 ajax

function ajax(method, url){
	return new Promise((resolve, reject) => {
		let xhr = new XMLHttpRequest()
		xhr.open(method, url, true)
		xhr.onreadystatechange = function(){
			if(this.readyState === 4 && this.status === 200){
				resolve(this.responseText)
			}
		}
		xhr.send(null)
	})
}

数组去重

// indexOf 去重
function qu(arr){
	let res = []
	arr.forEach((item) => {
		if(res.indexOf(item) === -1){
			res.push(item)
		}
	})
	return res
}
// ES6 去重
[...new Set(arr)]

深拷贝和浅拷贝

// 1.深拷贝
// 方法1
let newObj = JSON.parse(JSON.stringify(obj))
// 方法2
function deepClone(obj){
	let newObj = Array.isArray(obj) ? [] : {}
	for(let i in obj){
		newObj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
	}
	return newObj
}
// 2.浅拷贝
// 方法1
let newObj = {...obj}
// 方法2
let newObj = Object.assign({}, obj)

函数柯里化

// 将接受多个参数的函数转换成接受一个或多个参数的函数,并返回新的函数,等获得足够的参数后执行该函数
function curry(func, ...arg){
	return function(){
		let args = arg.concat([].slice.call(arguments))
		if(args.length >= func.length){
			func.apply(this, args)
		} else {
			return curry(func, ...args)
		}
	}
}

数组扁平化

function flatten(arr){
	let res = []
	while(arr.length > 0){
		let tmp = arr.pop()
		if(Array.isArray(tmp)){
			arr.push(...tmp)
		}else{
			res.unshift(tmp)
		}
	}
	return res
}

未完,待续…


如有错误,希望指正,不胜感激!

### 代码面试真题与练习题 在技术面试中,代码是一项重要的考核环节。以下是几类常见代码题目及其应用场景: #### 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); }; } ``` --- ### 总结 以上列举了几种类别的代码题目,涵盖了数组操作、数据结构与算法、字符串处理等多个领域。通过不断练习这些题目,可以有效提升编码能力和应对面试的信心。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值