Расширенная функция рукописного ввода JavaScript

Необходимость в продвинутом JavaScript

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

Будь то самосовершенствование или преодоление собеседований, следующие рукописные функции должны быть освоены каждым фронтенд-программистом.

1. Рукописно подать заявку, позвонить, связать

  每个Function对象都存在apply()、call()、bind() 方法,其作用都是可以在特定的作用域
  中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
复制代码
Сходства и различия между apply, call и bind
  1. 三者都可以改变this的指向,第一个参数都是this,如果指向是null或者undefined则指向window
  2.  apply的参数是数组,call是列表,而bind可以多次传入
  3.  apply和call是改变this的指向之后直接运行函数,而bind则是返回绑定之后的函数
复制代码
Справочный код для реализации применения
/**
 * 手写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
复制代码
применить эффект выполнения кода

изображение.png

Справочный код для реализации вызова
/**
 * 手写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
复制代码
Эффект выполнения кода вызова

изображение.png

Справочный код для реализации привязки
/**
 * 手写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
复制代码
Эффект выполнения кода привязки

изображение.png

2. Рукописный новый

Что делает новое ключевое слово, когда оно выполняется?
1. 创建了一个新对象
2. 将这个新对象与构造函数用原型链链接起来
3. 将构造函数的this指向新的对象,执行构造函数的代码赋值
4. 如果构造函数没有返回一个对象就返回新创建的对象否则返回构造函数返回的对象
复制代码
Рукописный новый ссылочный код
/***
 * 手写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());
复制代码
Справочная диаграмма результатов выполнения кода

результат.png

Принципиальная схема цепи прототипа

Lian.webp

3. Рукописный экземпляр

    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 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 )
复制代码
Скриншот результата выполнения кода

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

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");
复制代码
Результат выполнения написанного от руки кода защиты от сотрясений

изображение.png

рукописный дроссель
/***
 * 手写节流
 * 这里只需要注意和防抖不同的时 不会清除定时器
 */
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. Вручную внедрить ajax

    AJAX 的全称为 Asynchronous JavaScript + XML, 最重要的要属 XHR(XMLHttpRequest)
    XMLHttpRequest通过不刷新页面请求特定URL,获取数据。
复制代码
Предпосылки для реализации
  1. XMLHttpRequest() конструктор

  2. XMLHttpRequest.onreadystatechangeИнициировать событие при изменении кода состояния (поддерживается всеми браузерами)

  3. XMLHttpRequest.readyState код состояния запроса

изображение.png

  1. XMLHttpRequest.status Код состояния ответа возвращает стандартный код состояния HTTP.

изображение.png

  1. Другие параметры ответа на запрос

     XMLHttpRequest.response 这个是整个响应实体
     XMLHttpRequest.responseText 返回 `DOMString`
     XMLHttpRequest.timeout 超时时间
     XMLHttpRequest.upload 上传进度
    复制代码
  2. Глядя на общие методы

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" );
复制代码
Реализовать ajax на основе вышеуказанного API
    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()
            }
        }
    }
}
复制代码

Подведем итог

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

рекомендация

отjuejin.im/post/7086717540029693966