Função JavaScript avançada de escrita manual

A necessidade de JavaScript avançado

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

Seja para auto-aperfeiçoamento ou para lidar com entrevistas, as seguintes funções manuscritas devem ser dominadas por todo programador front-end

1. Inscrição manuscrita, chamada, vinculação

  每个Function对象都存在apply()、call()、bind() 方法,其作用都是可以在特定的作用域
  中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
复制代码
Semelhanças e diferenças entre aplicar, chamar e vincular
  1. 三者都可以改变this的指向,第一个参数都是this,如果指向是null或者undefined则指向window
  2.  apply的参数是数组,call是列表,而bind可以多次传入
  3.  apply和call是改变this的指向之后直接运行函数,而bind则是返回绑定之后的函数
复制代码
Código de referência para implementação de aplicação
/**
 * 手写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
复制代码
aplicar efeito de execução de código

imagem.png

Código de referência para implementação de chamada
/**
 * 手写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
复制代码
Efeito de execução de código de chamada

imagem.png

Código de referência para implementação de vinculação
/**
 * 手写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
复制代码
Efeito de execução de código de ligação

imagem.png

2. Novo manuscrito

O que a nova palavra-chave faz quando é executada?
1. 创建了一个新对象
2. 将这个新对象与构造函数用原型链链接起来
3. 将构造函数的this指向新的对象,执行构造函数的代码赋值
4. 如果构造函数没有返回一个对象就返回新创建的对象否则返回构造函数返回的对象
复制代码
Novo código de referência manuscrito
/***
 * 手写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());
复制代码
Diagrama de referência do resultado da execução do código

resultado.png

Diagrama esquemático da cadeia de protótipos

lian.webp

3. Instância manuscrita de

    typeof 可以判断基本数据类型 但是null 返回的也是object 不能识别 引用数据类型
    instanceof 可以准确的判断引用数据类型不可以判断 基本数据类型
    instanceof是用于检测构造函数的prototype是否出现某个实例对象的原型链上
复制代码
Código de referência
/**
* 手写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 )
复制代码
Captura de tela do resultado da execução do código

imagem.png 根据上面的代码打印结果 需要注意的是:万物皆对象,包括数组,如果存在一个变量(arrOrObj)可能为array或者object 如果使用instanceof 去判断,一定需要先判断是否为数组先,否则 arrOrObj instanceof Object 一定为true 就无法区分 array和object

4. Estabilização e limitação de caligrafia

    持续的触发某一事件,延迟n秒后执行回调,在未到n秒再次触发,会从新出发倒计时
    持续的触发某一时间,延迟n秒后执行回调,在未达到n秒再次出发,不会重新计时
复制代码
Use cenários para ambos

防抖Pode ser usado para comportamento ativo do usuário imprevisível, como conteúdo de entrada do usuário para os resultados da pesquisa dinâmica do servidor. A velocidade de digitação do usuário é imprevisível e irregular.

节流Ele pode ser usado para alguns comportamentos não ativos do usuário ou comportamentos ativos previsíveis do usuário, como enviar uma solicitação de pontos enterrados quando o usuário desliza a janela do produto, e o deslizamento de altura fixa é uma lógica conhecida e tem regularidade.

节流e 防抖é também uma aplicação de fechos

Referência de código anti-vibração manuscrita
/***
 * 手写防抖
 */
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");
复制代码
Resultado da execução do código anti-shake manuscrito

imagem.png

estrangulamento manuscrito
/***
 * 手写节流
 * 这里只需要注意和防抖不同的时 不会清除定时器
 */
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. Implemente manualmente o ajax

    AJAX 的全称为 Asynchronous JavaScript + XML, 最重要的要属 XHR(XMLHttpRequest)
    XMLHttpRequest通过不刷新页面请求特定URL,获取数据。
复制代码
Pré-requisitos para Implementação
  1. XMLHttpRequest() é um construtor

  2. XMLHttpRequest.onreadystatechangeAcionar um evento quando o código de status for alterado (suportado por todos os navegadores)

  3. XMLHttpRequest.readyState o código de status da solicitação

imagem.png

  1. XMLHttpRequest.status O código de status de resposta retorna o código de status HTTP padrão

imagem.png

  1. Outros parâmetros de resposta da solicitação

     XMLHttpRequest.response 这个是整个响应实体
     XMLHttpRequest.responseText 返回 `DOMString`
     XMLHttpRequest.timeout 超时时间
     XMLHttpRequest.upload 上传进度
    复制代码
  2. Olhando para métodos comuns

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" );
复制代码
Implemente o ajax com base na API acima
    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()
            }
        }
    }
}
复制代码

Resumir

    欢迎提出更好的思路以及其他必备手写功能
    
复制代码

Acho que você gosta

Origin juejin.im/post/7086717540029693966
Recomendado
Clasificación