JS 手写call 、 apply 、 bind 、 new 、防抖debounce 、节流throttle(内含闭包原理解释)
**这里很多手写代码都是基于闭包,闭包如何能保持访问外层函数的变量?

**执行栈会将调用到的函数的执行上下文( 变量环境、词法环境、this、outer), 压入执行的顺序:全局windows -> closezure函数 -> increase函数 只要increase继续调用,执行栈就无法跨过它销毁closezure的执行上下文,即可以继续访问外层函数变量
手写call
// 手写 call
Function.prototype.mycall = function(){
var args = Array.from(arguments)
var obj = args.slice(0,1)[0]
var fn = this
if(!obj) obj = window
obj.fn = fn
args = args.slice(1)
console.log(args)
let ret = obj.fn(...args)
delete obj.fn
return ret
}
function fn(){
console.log(this.name)
}
var o = {name : 'lhx'}
fn.mycall(null)
ES6 ...扩展运算符 , 放在函数定义中可以将剩余参数表示为 Aarry对象;如果是给函数传参时使用,则可以将 Array数组解析为 ',' 分隔的参数传递给函数
手写apply
Function.prototype.myapply = function(context,arg){
var args = Array.from(arg)
var obj = context ? context : window
var fn = this
obj.fn = fn
let ret = obj.fn(...args)
delete obj.fn
return ret
}
手写bind
Function.prototype.mybind = function(context){
var args = Array.from(arguments).slice(1)
var obj = context ? JSON.parse(JSON.stringify(context)) : window
var fn = this
/* 这里 bind 的 2 个复杂点:
*****返回的是一个函数,并不是直接执行的结果
*****返回的函数仍然可以传参
*****这里使用闭包来 封装
*/
function newfn(){
args = args.concat(Array.from(arguments))
obj.fn = fn
return obj.fn(...args)
}
return newfn
}
var o = {
name : 'lxs',
getname : function(age,sex){ console.log(this.name+age+sex) }
}
var b = {
name : 'bbb'
}
var gn = o.getname
var gnb = gn.mybind(b , '18' )
gnb('nam')
手写new
function myNew(constructFn){
// 首先创建一个新对象
var newO = {}
constructFn.apply(newO , Array.from(arguments).slice(1))
// 满足 instanceof 判断要求
newO.__proto__ = constructFn.prototype
return newO
}
function Person(name, age){
this.name = name
this.age = age
}
var p = myNew(Person,'lhx',12)
var p2 = new Person()
// 测试
console.log(p instanceof Person)
手写防抖debounce :在 wait 等待时间内,如果再次触发则会重新计时
使用场景:查询输入框连续敲击,敲完之后再去查询,避免资源浪费
function debounce(fn,wait){
var st = null
return function(){
if(st){
clearInterval(st)
st = setTimeout(()=>{
fn()
clearInterval(st)
},wait)
}
}
}
function debounce(fn,wait){
var st = null
return function(){
if(st){
clearInterval(st)
st = setTimeout(()=>{
fn()
clearInterval(st)
},wait)
}
}
}
手写节流throttle : 在 wait 时间内,只会触发一次
使用场景:鼠标 mousemove 事件,避免大量占用 JS 引擎线程
function throttle(fn,wait){
var st = null, start = (new Date).getDate()
return function(){
var end = (new Date).getDate()
if(end-start > wait){
start = (new Date).getDate()
st = setTimeout(()=>{
fn()
clearInterval(st)
},wait)
}
}
}
function throttle(fn,wait){
var st = null, start = (new Date).getDate()
return function(){
var end = (new Date).getDate()
if(end-start > wait){
start = (new Date).getDate()
st = setTimeout(()=>{
fn()
clearInterval(st)
},wait)
}
}
}
手写interator:
你让它动(.next)一下,它就动一下
function myInterator(arr){
var list = Array.from(arr)
let length = list.length
let curIndex = 0
this.next = function(){
if(curIndex === length){
return "done"
}
// 创造了一个没有 原型链的空对象
let ret = Object.create(null)
ret.value = list[curIndex++]
ret.done = false
return ret
}
}
var testIt = new myInterator([1,2,3])
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
function myInterator(arr){
var list = Array.from(arr)
let length = list.length
let curIndex = 0
this.next = function(){
if(curIndex === length){
return "done"
}
// 创造了一个没有 原型链的空对象
let ret = Object.create(null)
ret.value = list[curIndex++]
ret.done = false
return ret
}
}
var testIt = new myInterator([1,2,3])
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
console.log(testIt.next());
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人