js进阶手写常见函数

JavaScript进阶的必要性

无论是学习react还是vue,它们都是js的应用框架。剥去他们的壳子看到的始终是js,所以作为一个前端大厨必须要熟练掌握好js这个大勺,才能烧出一顿好菜

无论是自我提升还是应付面试以下这些手写功能是每一个前端程序员必须掌握的

1. 手写apply、call、bind
 每个Function对象都存在apply()、call()、bind() 方法,其作用都是可以在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。 
apply、call、bind 的异同
 1. 三者都可以改变this的指向,第一个参数都是this,如果指向是null或者undefined则指向window2.apply的参数是数组,call是列表,而bind可以多次传入3.apply和call是改变this的指向之后直接运行函数,而bind则是返回绑定之后的函数 
apply实现的参考代码
/** * 手写apply */
window.name='gy' // 全局变量 
let obj={name:'ckx'
}

var func=function(b,c){console.log(`this=`, this)console.log(this.name,b,c)return 1
}

func('24','hz') //gy 24 hz

func.apply(obj,['24','hz']) // ckx 24 hz

let newObj={name:'xmx',age:24
}
Function.prototype.myApply=function(base,args){// 1. 如果指向是null 或者undefined 则指向windowbase=base || window// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性base.fn=this// 3.执行函数,调用base.fn时,fn中的函数指向 base对象let result=base.fn(...args)// 4. 删除base的fn属性delete base.fn// 5. 返回result 结果returnresult
}

func.myApply(newObj,['55','yw']) // xmx 55 yw 
apply代码执行效果
call 实现的参考代码
/** * 手写call */
window.name='gy' // 全局变量 
let obj={name:'ckx'
}

var func=function(b,c){console.log(`this=`, this)console.log(this.name,b,c)return 1
}

func('24','hz') //gy 24 hz

func.call(obj,'24','hz') // ckx 24 hz

let newObj={name:'xmx',age:24
}
// call 和apply需要注意参数的格式即可
Function.prototype.myCall=function(base,...args){// 1. 如果指向是null 或者undefined 则指向windowbase=base || window// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性base.fn=this// 3.执行函数,调用base.fn时,fn中的函数指向 base对象let result=base.fn(...args)// 4. 删除base的fn属性delete base.fn// 5. 返回result 结果returnresult
}

func.myCall(newObj,'55','yw') // xmx 55 yw 
call代码执行效果
bind实现的参考代码
/** * 手写bind */
window.name = "gy"; // 全局变量
let obj = {name: "ckx",
};

var func = function (b, c,d) {console.log(`this=`, this);console.log(this.name, b, c,d);return 1;
};

func("24", "hz",26); //gy 24 hz 26

let funcRes = func.bind(obj, "24", "hz");
funcRes(24);// ckx 24 hz 24

let newObj = {name: "xmx",age: 24,
};
// 注意bind 返回的时绑定的函数以及可以多次传递参数
Function.prototype.myBind = function (base, ...args1) {return (...args2) => {// 1. 如果指向是null 或者undefined 则指向windowbase = base || window;// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性base.fn = this;// 3.执行函数,调用base.fn时,fn中的函数指向 base对象let result = base.fn(...args1,...args2);// 4. 删除base的fn属性delete base.fn;// 5. 返回result 结果return result;};
};
let myfuncRes=func.myBind(newObj, "55", "yw")
myfuncRes(24) // xmx 55 yw 24 
bind代码执行效果
2. 手写new
new关键字执行时做了哪些
1. 创建了一个新对象
2. 将这个新对象与构造函数用原型链链接起来
3. 将构造函数的this指向新的对象,执行构造函数的代码赋值
4. 如果构造函数没有返回一个对象就返回新创建的对象否则返回构造函数返回的对象 
手写new参考代码
/*** * 手写new关键字执行 */

function Person(name,age) {this.name = name;
}
Person.prototype.getName = function () {return this.name;
};
let a = new Person('gy');
console.log(a);
console.log(a.getName());

const myNew = (Func, ...args) => {let newObj = {};newObj.__proto__=Func.prototypelet result=Func.apply(newObj,args)returntypeof result == Object ? result: newObj
};
let b = myNew(Person,'gy1')
console.log(b);
console.log(b.getName()); 
代码执行结果参考图
原型链示意图
3. 手写instanceof
 typeof 可以判断基本数据类型 但是null 返回的也是object 不能识别 引用数据类型instanceof 可以准确的判断引用数据类型不可以判断 基本数据类型instanceof是用于检测构造函数的prototype是否出现某个实例对象的原型链上 
参考代码
/*** 手写instanceof*/
let obj= { label:'gy' }
let arr= ['hello']

let result = obj instanceof Object
let result1 = arr instanceof Array
let result2 = arr instanceof Object
let result3 = obj instanceof Array

console.log('result=',result )
console.log('result1=',result1 )
console.log('result2=',result2 )
console.log('result3=',result3 )

const myInstanceof = (left,right)=>{if(typeof left != 'object' || left == null ) return falselet proto= Object.getPrototypeOf(left)while(true){if(proto==null) return falseif(proto==right.prototype) return trueproto=Object.getPrototypeOf(proto)}
}

const myResult= myInstanceof(obj,Object)
const myResult1= myInstanceof(arr,Array)
const myResult2= myInstanceof(arr,Object)
const myResult3= myInstanceof(obj,Array)

console.log('myRsult=',myResult )
console.log('myResult1=',myResult1 )
console.log('myResult2=',myResult2 )
console.log('myResult3=',myResult3 ) 
代码执行结果截图
4. 手写防抖和节流
 持续的触发某一事件,延迟n秒后执行回调,在未到n秒再次触发,会从新出发倒计时持续的触发某一时间,延迟n秒后执行回调,在未达到n秒再次出发,不会重新计时 
两者的使用场景

防抖可能用于无法预知的用户主动行为,如用户输入内容去服务端动态搜索结果。用户打字的速度等是无法预知的,具有非规律性。

节流可能用于一些非用户主动行为或者可预知的用户主动行为,如用户滑动商品橱窗时发送埋点请求、滑动固定的高度是已知的逻辑,具有规律性。

节流防抖也是闭包的应用

手写防抖代码参考
/*** * 手写防抖 */
const debounce = (func, delay) => {let timer = null;return function (...args) {if (timer) {clearTimeout(timer);timer = null;}timer = setTimeout(() => {func(args);}, delay);};
};
const getfn = (data) => {console.log(data);
};
debounce(getfn, 2000)("gy"); 
手写防抖代码执行结果
手写节流
/*** * 手写节流 * 这里只需要注意和防抖不同的时 不会清除定时器 */
const throttle = (func, delay) => {let flag = false;return function (...args) {if (flag)returnflag=truesetTimeout(() => {func(args);flag=false}, delay);};
};
const getfn = (data) => {console.log(data);
};
throttle(getfn, 2000)("gy"); 
5. 手动实现ajax
 AJAX 的全称为 Asynchronous JavaScript + XML, 最重要的要属 XHR(XMLHttpRequest)XMLHttpRequest通过不刷新页面请求特定URL,获取数据。 
实现的必备条件

1.XMLHttpRequest() 是一个构造函数2.XMLHttpRequest.onreadystatechange 状态码变化时触发事件(所有浏览器支持)3.XMLHttpRequest.readyState 请求的状态码

4.XMLHttpRequest.status 响应状态码 返回标准的HTTP 状态码

5.其他的请求响应参数XMLHttpRequest.response 这个是整个响应实体XMLHttpRequest.responseText 返回 `DOMString`XMLHttpRequest.timeout 超时时间XMLHttpRequest.upload 上传进度 6.在看看常用方法 open()// method/url 是必须的 xhr.open(method, url, async, user, password); send()// body 可选默认为null // 可以是 Blob, BufferSource (en-US), FormData, // URLSearchParams, 或者 USVString 对象. XMLHttpRequest.send(body); setRequestHeader()XMLHttpRequest.setRequestHeader(header, value); // 例如 XMLHttpRequest.setRequestHeader (“content-type”, “application/x-www-form-urlencoded” );###### 基于以上API实现 ajax

 1.构造一个请求 XMLHttpRequest
 2.初始化一个请求 open
 3.监听请求 onreadystatechange
 4.发送该请求 send 
/*** 手写一个ajax*/
const myAjax =(url,methods,header,success,error)=>{// 创建一个请求let request=new XMLHttpRequest()// 设置请求头for (const key in header) {request.setRequestHeader(key,header[key])}// 初始化请求request.open(methods,url)// 发送请求request.send()// 监听请求 onreadystatechangerequest.onreadystatechange =function(){if(request.readyState==4){if(request.status==200){success(request.response)}else {error()}}}
} 

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值