首页 > 其他分享 >【面试题】 面试手写JS 十六题(必看)

【面试题】 面试手写JS 十六题(必看)

时间:2022-11-05 17:36:16浏览次数:104  
标签:function 面试题 return 必看 args arr JS let key


 

1、手写实现防抖和节流

1.1 实现防抖函数

防抖函数原理:把触发非常频繁的事件合并成一次去执行 在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算

// func是用户传入需要防抖的函数
// time是等待时间
const debounce = (callback, time = 50) => {
let timer = 0
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
callback.apply(this, args)
}, time)
}
}
复制代码

1.2 实现节流函数

节流函数原理: 指频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数。

// func是用户传入需要防抖的函数
// wait是等待时间
const throttle = (func, wait = 50) => {
let lastTime = 0
return function(...args) {
let now = +new Date()
if (now - lastTime > wait) {
lastTime = now
func.apply(this, args)
}
}
}
复制代码

2、手写深拷贝

调用深拷贝方法,若属性为值类型,则直接返回;若属性为引用类型,则递归遍历。这就是我们在解这一类题时的核心的方法。

function deepClone(obj) {
if(typeof obj !== 'object' || obj === null) {
return obj
}
let copy = {}
if(obj.constructor === Array) {
copy = []
}
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
copy[key] = deepClone(obj[key])
}
}
return copy
}
复制代码

3、手写实现call方法

call做了什么

  1. 将函数设为对象的属性
  2. 执行和删除这个函数
  3. 指定​​this​​到函数并传入给定参数执行函数
  4. 如果不传入参数,默认指向为 ​​window​
Function.prototype.myCall = function(context = window, ...args) {
if (typeof this !== "function") {
throw new Error('type error')
}
let key = Symbol('key')
context[key] = this;
let result = context[key](...args);
delete context[key];
return result;
};
复制代码

4 手写apply方法

Function.prototype.myApply = function(context = window, args) {
let key = Symbol('key')
context[key] = this;
// let args = [...arguments].slice(1)
let result = context[key](...args);
delete context[key];
return result;
}
复制代码

5、手写forEach方法

Array.prototype.myForEach = function(callback, context=window) {
let self = this,
i = 0,
len = self.length;

for(;i<len;i++) {
typeof callback == 'function' && callback.call(context,self[i], i)
}
}
复制代码

6、手写filter方法

Array.prototype.myFilter=function(callback, context=window){

let len = this.length
newArr = [],
i=0

for(; i < len; i++){
if(callback.apply(context, [this[i], i , this])){
newArr.push(this[i]);
}
}
return newArr;
}
复制代码

7、手写reduce方法

Array.prototype.myReduce = function(fn, initialValue) {
var arr = Array.prototype.slice.call(this);
var res, startIndex;
res = initialValue ? initialValue : arr[0];
startIndex = initialValue ? 0 : 1;
for(var i = startIndex; i < arr.length; i++) {
res = fn.call(null, res, arr[i], i, this);
}
return res;
}
复制代码

8 查找字符串中出现最多的字符和个数

字符最多的是char,出现了num次

function myString(str){
let num = 0;
let char = '';
let re = /(\w)\1+/g;
str.replace(re,($0,$1) => {
if(num < $0.length){
num = $0.length;
char = $1;
}
});
return {num, char}
}

复制代码

9 冒泡排序

冒泡排序的原理如下,从第一个元素开始,把当前元素和下一个索引元素进行比较。如果当前元素大,那么就交换位置,重复操作直到比较到最后一个元素,那么此时最后一个元素就是该数组中最大的数。下一轮重复以上操作,但是此时最后一个元素已经是最大数了,所以不需要再比较最后一个元素,只需要比较到 ​​length - 1​​ 的位置

function bubbleSort(list) {
var n = list.length;
if (!n) return [];

for (var i = 0; i < n; i++) {
// 注意这里需要 n - i - 1
for (var j = 0; j < n - i - 1; j++) {
if (list[j] > list[j + 1]) {
var temp = list[j + 1];
list[j + 1] = list[j];
list[j] = temp;
}
}
}
return list;
}
复制代码

10 快速排序

快排的原理如下。随机选取一个数组中的值作为基准值,从左至右取值与基准值对比大小。比基准值小的放数组左边,大的放右边,对比完成后将基准值和第一个比基准值大的值交换位置。然后将数组以基准值的位置分为两部分,继续递归以上操作

function quickSort(arr) {
if (arr.length<=1){
return arr;
}
var baseIndex = Math.floor(arr.length/2);
var base = arr.splice(baseIndex,1)[0];
var left=[];
var right=[];
for (var i = 0; i<arr.length; i++){
if (arr[i] < base){
left.push(arr[i]);
}
}else{
right.push(arr[i]);,
}
return quickSort(left).concat([base],quickSort(right));
}
复制代码

11 插入排序

function insertSort(arr) {
for (let i = 1; i < arr.length; i++) {
let j = i;
let target = arr[j];
while (j > 0 && arr[j - 1] > target) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = target;
}
return arr;
}
复制代码

12 对象扁平化

function objectFlat(obj = {}) {
const res = {}
function flat(item, preKey = '') {
Object.entries(item).forEach(([key, val]) => {
const newKey = preKey ? `${preKey}.${key}` : key
if (val && typeof val === 'object') {
flat(val, newKey)
} else {
res[newKey] = val
}
})
}
flat(obj)
return res
}
复制代码

13、手写发布订阅模式

  • 创建一个对象
  • ​on​​​方法用来把回调函数​​fn​​都加到缓存列表中
  • ​emit​​​ 根据​​key​​值去执行对应缓存列表中的函数
  • ​off​​​方法可以根据​​key​​值取消订阅
class EventEmiter {
constructor() {
this._events = {}
}
on(eventName,callback) {
if(!this._events) {
this._events = {}
}
this._events[eventName] = [...(this._events[eventName] || []),callback]
}
emit(eventName, ...args) {
if(!this._events[eventName]) {
return
}
this._events[eventName].forEach(fn=>fn(...args))
}
off(eventName,cb) {
if(!this._events[eventName]) {
return
}
this._events[eventName] = this._events[eventName].filter(fn=>fn != cb && fn.l != cb)
}
once(eventName,callback) {
const one = (...args)=>{
callback(args)
this.off(eventName,one)
}
one.l = callback
this.on(eventName,one)
}
}
复制代码

14、手写Ajax

  • 创建 ​​XMLHttpRequest​​ 实例
  • 发出 HTTP 请求
  • 服务器返回 XML 格式的字符串
  • JS 解析 XML,并更新局部页面
  • 不过随着历史进程的推进,XML 已经被淘汰,取而代之的是 JSON。
function ajax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
resolve(JSON.parse(xhr.responseText))
} else {
reject('请求出错')
}
}
}
xhr.send()
})
}
复制代码

15、数组去重

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

16、实现new的过程

new操作符做了这些事:

  • 创建一个全新的对象
  • 这个对象的​​__proto__​​要指向构造函数的原型prototype
  • 执行构造函数,使用 ​​call/apply​​ 改变 this 的指向
  • 返回值为​​object​​​类型则作为​​new​​方法的返回值返回,否则返回上述全新对象
function myNew(fn, ...args) {
let newObj = Object.create(fn.prototype);
let res = fn.apply(newObj, args);
return typeof res === 'object' ? res: newObj;
}

 


标签:function,面试题,return,必看,args,arr,JS,let,key
From: https://blog.51cto.com/u_14627797/5826030

相关文章

  • 【面试题】面试小技巧:如果有人问你 xxx 技术是什么?
    背景在前几天,有一个朋友突然问了我一个问题,说如果有人问你“React是什么?你怎么回答。 ”,我当时脱口而出“React是一个网页UI框架一个,它的特点声明式、组件化、组件化、......
  • 【面试题】说说JS中的this指向问题
    JS中的this指向问题this的指向问题全局作用域在JS中,全局的变量和函数附着在​​global​​​对象上,全局对象在浏览器环境下是​​window​​对象。在全局作用域中,​​this​......
  • 野花--input获取焦点,改变父元素,改变兄弟元素,不使用js来实现
    :focus-within:focus-within是一个CSS伪类,表示一个元素获得焦点,或该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配:focus伪类。(shadowDOM树(en-U......
  • js的bind 的原理
    js的bind方法主要绑定this的指向bind方法也会返回是个bind后的函数。知道它功能我们就可以自定义bind功能letobject={name:'jeff'}functionfn(){console.log(thi......
  • CSS & JS Effect – Textarea Autoresize
    前言这是一个很普遍的体验,而且实现起来也很简单哦 参考YouTube– HowtoAutoResizeTextareausingHTMLCSS&JavaScript 效果我故意加了border和pad......
  • Jmeter断言之Json Assertion
    现在大部分的程序都是通过json格式返回数据,所以JsonAssertion也是非常重要的一个组件添加JsonAssertion组件使用方法 ......
  • JS中的变量声明
    一、引入1.定义:在JavaScript中创建变量被称为“声明”变量。JavaScript中变量声明又分为显示声明和隐式声明。其中显示声明中,被“声明”变量之前的关键词有var、let、cons......
  • 使用nvm配置nodejs,已经nodejs使用的初始化步骤
    <-----------------------------------------nvm是什么------------------------------------------------->nvm:进行node版本切换管理手动配置nvm,需要进入地址https://gi......
  • JS代码压缩
    JS代码压缩本文分享一种技术,用于实现JS代码压缩。该技术使用LZW算法。LZW算法又叫“串表压缩算法”,简而言之,通过建立一个字符串表,用较短的代码来表示较长的字符串来实现压缩......
  • etherjs基本用法
    前言:直到2022.11.5才知道etherjs真正的用法,之前只用过web3.js,原来两个库是并行的,选择一个就好。 连接etherjs需要的几要素:infra_keyprivate_keyrpc_url 连接合约......