Le besoin de JavaScript avancé
无论是学习react还是vue,它们都是js的应用框架。剥去他们的壳子看到的始终是js,所以作为一个前端大厨必须要熟练掌握好js这个大勺,才能烧出一顿好菜
Qu'il s'agisse d'auto-amélioration ou de faire face à des entretiens, les fonctions manuscrites suivantes doivent être maîtrisées par chaque programmeur frontal
1. Manuscrit appliquer, appeler, lier
每个Function对象都存在apply()、call()、bind() 方法,其作用都是可以在特定的作用域
中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
复制代码
Similitudes et différences entre appliquer, appeler et lier
1. 三者都可以改变this的指向,第一个参数都是this,如果指向是null或者undefined则指向window
2. apply的参数是数组,call是列表,而bind可以多次传入
3. apply和call是改变this的指向之后直接运行函数,而bind则是返回绑定之后的函数
复制代码
Code de référence pour l'implémentation de l'application
/**
* 手写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 则指向window
base=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 结果
return result
}
func.myApply(newObj,['55','yw']) // xmx 55 yw
复制代码
appliquer l'effet d'exécution du code
Code de référence pour la mise en œuvre de l'appel
/**
* 手写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 则指向window
base=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 结果
return result
}
func.myCall(newObj,'55','yw') // xmx 55 yw
复制代码
Effet d'exécution du code d'appel
Code de référence pour l'implémentation de la liaison
/**
* 手写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 则指向window
base = 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
复制代码
Lier l'effet d'exécution du code
2. Manuscrit nouveau
Que fait le nouveau mot-clé lorsqu'il s'exécute ?
1. 创建了一个新对象
2. 将这个新对象与构造函数用原型链链接起来
3. 将构造函数的this指向新的对象,执行构造函数的代码赋值
4. 如果构造函数没有返回一个对象就返回新创建的对象否则返回构造函数返回的对象
复制代码
Nouveau code de référence manuscrit
/***
* 手写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.prototype
let result=Func.apply(newObj,args)
return typeof result == Object ? result: newObj
};
let b = myNew(Person,'gy1')
console.log(b);
console.log(b.getName());
复制代码
Diagramme de référence des résultats d'exécution du code
Schéma de principe de la chaîne prototype
3. Exemple manuscrit de
typeof 可以判断基本数据类型 但是null 返回的也是object 不能识别 引用数据类型
instanceof 可以准确的判断引用数据类型不可以判断 基本数据类型
instanceof是用于检测构造函数的prototype是否出现某个实例对象的原型链上
复制代码
Code de référence
/**
* 手写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 false
let proto= Object.getPrototypeOf(left)
while(true){
if(proto==null) return false
if(proto==right.prototype) return true
proto=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 )
复制代码
Capture d'écran du résultat de l'exécution du code
根据上面的代码打印结果 需要注意的是:万物皆对象,包括数组,如果存在一个变量(arrOrObj)可能为array或者object 如果使用instanceof 去判断,一定需要先判断是否为数组先,否则 arrOrObj instanceof Object 一定为true 就无法区分 array和object
4. Stabilisation et limitation de l'écriture manuscrite
持续的触发某一事件,延迟n秒后执行回调,在未到n秒再次触发,会从新出发倒计时
持续的触发某一时间,延迟n秒后执行回调,在未达到n秒再次出发,不会重新计时
复制代码
Utilisez des scénarios pour les deux
防抖
Peut être utilisé pour le comportement actif imprévisible de l'utilisateur, tel que le contenu d'entrée de l'utilisateur dans les résultats de recherche dynamiques du serveur. La vitesse de frappe de l'utilisateur est imprévisible et irrégulière.
节流
Il peut être utilisé pour certains comportements actifs non-utilisateurs ou comportements actifs prévisibles de l'utilisateur, tels que l'envoi d'une demande de points enterrés lorsque l'utilisateur fait glisser la fenêtre du produit, et la hauteur fixe coulissante est une logique connue et a une régularité.
节流
et 防抖
est aussi une application de fermetures
Référence manuscrite du code anti-tremblement
/***
* 手写防抖
*/
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");
复制代码
Résultat d'exécution du code anti-tremblement manuscrit
limitation manuscrite
/***
* 手写节流
* 这里只需要注意和防抖不同的时 不会清除定时器
*/
const throttle = (func, delay) => {
let flag = false;
return function (...args) {
if (flag) return
flag=true
setTimeout(() => {
func(args);
flag=false
}, delay);
};
};
const getfn = (data) => {
console.log(data);
};
throttle(getfn, 2000)("gy");
复制代码
5. Implémenter manuellement ajax
AJAX 的全称为 Asynchronous JavaScript + XML, 最重要的要属 XHR(XMLHttpRequest)
XMLHttpRequest通过不刷新页面请求特定URL,获取数据。
复制代码
Conditions préalables à la mise en œuvre
-
XMLHttpRequest()
est un constructeur -
XMLHttpRequest.onreadystatechange
Déclencher un événement lorsque le code d'état change (pris en charge par tous les navigateurs) -
XMLHttpRequest.readyState
le code d'état de la demande
XMLHttpRequest.status
Le code d'état de la réponse renvoie le code d'état HTTP standard
-
Autres paramètres de réponse à la demande
XMLHttpRequest.response 这个是整个响应实体 XMLHttpRequest.responseText 返回 `DOMString` XMLHttpRequest.timeout 超时时间 XMLHttpRequest.upload 上传进度 复制代码
-
Examen des méthodes courantes
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" );
复制代码
Implémenter ajax basé sur l'API ci-dessus
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()
// 监听请求 onreadystatechange
request.onreadystatechange =function(){
if(request.readyState==4){
if(request.status==200){
success(request.response)
}else {
error()
}
}
}
}
复制代码
Résumer
欢迎提出更好的思路以及其他必备手写功能
复制代码