Javascript常见面试手写题

Javascript常见面试手写题

欢迎Star ⭐️ github

通过自动化脚本,每次push会自动跑单测
100%单测通过,每一个方法都使用jest单元测试进行了验证

后续会持续更新

单测报告

每次push自动生成测试报告

函数

题目 描述
[1.防抖](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[2.节流](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[5.深浅拷贝](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[6.发布订阅](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[7.函数柯里化](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[8.组合函数](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[9.before函数](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)
[10.偏函数](#题目 描述 1.防抖 2.节流 5.深浅拷贝 6.发布订阅 7.函数柯里化 8.组合函数 9.before函数 10.偏函数)

数组

题目 描述
[3.数组去重](#题目 描述 3.数组去重 4.数组扁平化)
[4.数组扁平化](#题目 描述 3.数组去重 4.数组扁平化)

Javascript原理

题目 描述
[12.call](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)
[13.bind](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)
[14.apply](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)
[15.new](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)
[16.instanceof](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)
[17.模拟jsonp](#题目 描述 12.call 13.bind 14.apply 15.new 16.instanceof 17.模拟jsonp)

未分类

题目 描述
[11.AJAX](#题目 描述 11.AJAX)

1.防抖

js 复制代码
// 1. 防抖
export function debounce(fn, delay, options) {
  let timer = null;
  let shouldInvoke = options.immediately // 是否立即执行
  return function(...args) {
    if (shouldInvoke) {
      fn.call(this, ...args)
      shouldInvoke = false
    }
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.call(this, ...args)
      shouldInvoke = options.immediately
    }, delay)
  }
}

2.节流

js 复制代码
// 节流函数
export function throttle(fn, delay) {
  let timer = null
  return function (...args) {
    if (!timer) {
      fn.call(this, ...args)
      timer = setTimeout(() => {
        timer = null
      }, delay)
    } 
  }
}

3.数组去重

js 复制代码
export function uniqueArr(arr) {
  return [...new Set(arr)];
}

export function uniqueArr2(arr) {
  return arr.filter((value, index) => arr.indexOf(value) === index);
}

4.数组扁平化

js 复制代码
// 根据指定深度递归地将所有子数组元素拼接到新的数组中
// n默认1
export function flat(arr, n) {
  return arr.flat(n)
}

// 全部扁平化
export function flat2(arr) {
  while(arr.some(item => Array.isArray(item))) {
      arr = [].concat(...arr);
  }
  return arr;
}

// 递归法
export function flat3(arr, deep) {
  if (deep === 0) {
    return arr
  }
  let ret = []
  for (let i = 0 ; i < arr.length ; i ++){
    if (Array.isArray(arr[i])) {
      ret.push(...flat3(arr[i], deep - 1))
    } else {
      ret.push(arr[i])
    }
  }
  return ret
}

5.深浅拷贝

js 复制代码
export function deepClone(obj) {
  if (obj === null || typeof obj!== 'object') {
    return obj;
  }
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }
  const clonedObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clonedObj[key] = deepClone(obj[key]);
    }
  }
  return clonedObj;
}

6.发布订阅

js 复制代码
export class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
    return this;
  }

  emit(eventName,...args) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(callback => callback(...args));
    }
    return this;
  }

  off(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(
        cb => cb!== callback
      );
    }
    return this;
  }
}

// const emitter = new EventEmitter();

// const callback1 = (data) => {
//   console.log('Callback 1:', data);
// };

// const callback2 = (data) => {
//   console.log('Callback 2:', data);
// };

// emitter.on('event1', callback1);
// emitter.on('event1', callback2);

// emitter.emit('event1', 'Hello from event emitter!');

// emitter.off('event1', callback1);

// emitter.emit('event1', 'Another emit after removing callback1.');

7.函数柯里化

js 复制代码
export function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return function (...nextArgs) {
        return curried.apply(this, [...args,...nextArgs]);
      };
    }
  };
}

8.组合函数

js 复制代码
/**
 * 从右向左执行
 * https://juejin.cn/post/6844903910834962446
 */
export function compose(...fns) {
  if(fns.length === 0) {
    return val => val
  }
  return function(val) {
    fns.reverse().forEach(fn => {
      val = fn(val)
    })
    return val
  }
}

9.before函数

js 复制代码
/**
 * 指定函数调用次数
 */
export function before (fn, times) {
  return (...args) => {
    if (times === 0) return
    fn(...args)
    if (times > 0) {
      times-- 
    }
  }
}

10.偏函数

js 复制代码
export function partial(fn, ...arg) {
  return (...args) => {
    return fn(...arg, ...args)
  }
}

11.AJAX

js 复制代码
// get
export function ajaxGet(url, callback) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      callback(xhr.responseText);
    }
  };
  xhr.send();
}

// post
export function ajaxPost(url, data, callback) {
  const xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200 || xhr.status === 201) {
        callback(xhr.responseText);
      } else {
        console.error('Error in POST request:', xhr.statusText);
      }
    }
  };
  xhr.send(JSON.stringify(data));
}

12.call

js 复制代码
export function call(context, ...args) {
  if (context === null || context === undefined) {
    context = typeof window !== 'undefined' ? window : global
  } else {
    context = Object(context) // 原始值会被包装 如果是非原始值会直接返回
  }
  context.fn = this;
  let ret = context.fn(...args)
  delete context.fn
  return ret
}

13.bind

js 复制代码
export function bind(context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  let self = this
  let fBound = function (...args2) {
    return self.call(this instanceof self ? this : context, ...args, ...args2)
  }
  fBound.prototype = Object.create(self.prototype)
  return fBound
}

14.apply

js 复制代码
export function apply (context, argsArray) {
  if (context === null || context === undefined) {
    context = typeof window !== 'undefined' ? window : global
  }
  context.fn = this
  let ret = context.fn(...Array.from(argsArray))
  delete context.fn
  return ret
}

15.new

js 复制代码
export function _new(constructor, ...args) {  
  // let obj = {}                            // 1. 创建一个空对象({})
  // obj.__proto__ = constructor.prototype          // 2. 链接该对象到另外一个对象
  let obj = Object.create(constructor.prototype)    // 替代1 2
  const ret = constructor.call(obj, ...args) // 3. 将创建的空对象作为this的上下文
  return typeof ret === 'object' ? ret : obj // 4. 如果该函数没有返回对象,则返回this
}

16.instanceof

js 复制代码
export function _instanceof(V, F) {
  if (Object.prototype.toString.call(V) !== '[object Object]') {
    return false
  }
  let O = F.prototype
  if (Object.prototype.toString.call(O) !== '[object Object]') {
    return false
  }
  while(true) {
    V = Object.getPrototypeOf(V)
    if (V === null) return false
    if (V === O) return true
  }
}

17.模拟jsonp

js 复制代码
export function jsonp(url) {
  return new Promise((resolve, reject) => {
    // 创建一个唯一的回调函数名
    const uniqueCallbackName = `jsonp_callback_${Date.now()}_${Math.random().toString(36).substring(2)}`;

    // 创建一个 script 标签
    const script = document.createElement('script');
    script.src = `${url}?callback=${uniqueCallbackName}`;

    // 定义全局回调函数
    window[uniqueCallbackName] = function(data) {
      resolve(data);
      // 清除全局回调函数和 script 标签
      delete window[uniqueCallbackName];
      document.body.removeChild(script);
    };

    // 处理错误情况
    script.onerror = function() {
      reject(new Error('JSONP request failed'));
      delete window[uniqueCallbackName];
      document.body.removeChild(script);
    };

    // 将 script 标签添加到文档中
    document.body.appendChild(script);
  });
}
相关推荐
小马哥编程33 分钟前
Function.prototype和Object.prototype 的区别
javascript
王小王和他的小伙伴1 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱1 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿1 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
小k_不小2 小时前
C++面试八股文:指针与引用的区别
c++·面试
好名字08212 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光932 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
胡西风_foxww2 小时前
【ES6复习笔记】Class类(15)
javascript·笔记·es6·继承··class·静态成员
布兰妮甜3 小时前
使用 WebRTC 进行实时通信
javascript·webrtc·实时通信
艾斯特_3 小时前
JavaScript甘特图 dhtmlx-gantt
前端·javascript·甘特图