2021年的几次面试让我死磕了17道JS手写题!(上)

简介: 2021年的几次面试让我死磕了17道JS手写题!

1、浅拷贝、深拷贝的实现

浅拷贝

1. // 1. ...实现
2. let copy1 = {...{x:1}}
3. 
4. // 2. Object.assign实现
5. let copy2 = Object.assign({}, {x:1})

深拷贝


javascript深拷贝和浅拷贝以及实现方法(推荐)_纸飞机博客-CSDN博客_js浅拷贝和深拷贝的区别

深拷贝和浅拷贝的区别?浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用。深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”。为什么要用深拷贝?我们希望在改变新的数组(对象)的时候,不改变原数组(对象)一般是针对Array和Object类型数据的复制对象深拷贝方法1.JSON的方式实现function deepClone2(obj) { let _obj = JSON.st

https://blog.csdn.net/qq_32442973/article/details/118584594


2、手写防抖节流函数

javascript的防抖和节流深入理解_纸飞机博客-CSDN博客

基本概念函数防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。函数节流(throttle):高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。函数防抖(debounce)与 函数节流(throttle)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。函数防抖(debounce)实现方式:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法

https://blog.csdn.net/qq_32442973/article/details/118739927


3、instanceof (考察对原型链的理解)

instanceof作用:判断一个实例是否是其父类或者祖先类型的实例

instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype查找失败,返回 false。


let myInstanceof = (target,origin) => {
     while(target) {
         if(target.__proto__===origin.prototype) {
            return true
         }
         target = target.__proto__
     }
     return false
}
let a = [1,2,3]
console.log(myInstanceof(a,Array));  // true
console.log(myInstanceof(a,Object));  // true

4、实现数组的map方法

Array.prototype.newMap = function(fn) {
   var newArr = [];
   for(var i = 0; i<this.length; i++){
     newArr.push(fn(this[i],i,this))
   }
   return newArr;
}

5、实现 new 方法

function createNew() {
    let obj = {}  // 1.创建一个空对象
    let constructor = [].shift.call(arguments) 
    // let [constructor,...args] = [...arguments]  
    obj.__proto__ = constructor.prototype  // 2.链接到原型
    let result = constructor.apply(obj, arguments)  // 3.绑定this值,为实例添加方法和属性
    // let result = constructor.apply(obj, args)   
    return typeof result === 'object' ? result : obj  // 4.返回新对象
}
function People(name,age) {
    this.name = name
    this.age = age
}
let peo = createNew(People,'Bob',22)
console.log(peo.name)
console.log(peo.age)

6、实现call&apply&bind

call

Function.prototype.myCall = function (context = window) {
  // 函数的方法,所以写在Fuction原型对象上
  if (typeof this !== "function") {
    // 这里if其实没必要,会自动抛出错误
    throw new Error("不是函数");
  }
  const obj = context || window; //这里可用ES6方法,为参数添加默认值,js严格模式全局作用域this为undefined
  obj.fn = this; //this为调用的上下文,this此处为函数,将这个函数作为obj的方法
  const arg = [...arguments].slice(1); //第一个为obj所以删除,伪数组转为数组
  res = obj.fn(...arg);
  delete obj.fn; // 不删除会导致context属性越来越多
  return res;
};

apply(arguments[this, [参数1,参数2.....] ])

Function.prototype.myApply = function (context) {
  // 箭头函数从不具有参数对象!!!!!这里不能写成箭头函数
  let obj = context || window;
  obj.fn = this;
  const arg = arguments[1] || []; //若有参数,得到的是数组
  let res = obj.fn(...arg);
  delete obj.fn;
  return res;
};
function f(a, b) {
  console.log(a, b);
  console.log(this.name);
}
let obj = {
  name: "张三",
};
f.myApply(obj, [1, 2]); //arguments[1]

bind

// 思路:类似call,但返回的是函数
Function.prototype.mybind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  let _this = this
  let arg = [...arguments].slice(1)
  return function F() {
    // 处理函数使用new的情况
    if (this instanceof F) {
      return new _this(...arg, ...arguments)
    } else {
      return _this.apply(context, arg.concat(...arguments))
    }
  }
}

更多实现:bind方法的实现

7、手动实现promise

// Promise/A+ 规范规定的三种状态
const STATUS = {
 PENDING: 'pending',
 FULFILLED: 'fulfilled',
 REJECTED: 'rejected'
}
class MyPromise {
 // 构造函数接收一个执行回调
 constructor(executor) {
     this._status = STATUS.PENDING // Promise初始状态
     this._value = undefined // then回调的值
     this._resolveQueue = [] // resolve时触发的成功队列
     this._rejectQueue = [] // reject时触发的失败队列
 // 使用箭头函数固定this(resolve函数在executor中触发,不然找不到this)
 const resolve = value => {
     const run = () => {
         // Promise/A+ 规范规定的Promise状态只能从pending触发,变成fulfilled
         if (this._status === STATUS.PENDING) {
             this._status = STATUS.FULFILLED // 更改状态
             this._value = value // 储存当前值,用于then回调
             // 执行resolve回调
             while (this._resolveQueue.length) {
                 const callback = this._resolveQueue.shift()
                 callback(value)
             }
         }
     }
     //把resolve执行回调的操作封装成一个函数,放进setTimeout里,以实现promise异步调用的特性(规范上是微任务,这里是宏任务)
     setTimeout(run)
 }
 // 同 resolve
 const reject = value => {
     const run = () => {
         if (this._status === STATUS.PENDING) {
         this._status = STATUS.REJECTED
         this._value = value
         while (this._rejectQueue.length) {
             const callback = this._rejectQueue.shift()
             callback(value)
         }
     }
 }
     setTimeout(run)
 }
     // new Promise()时立即执行executor,并传入resolve和reject
     executor(resolve, reject)
 }
 // then方法,接收一个成功的回调和一个失败的回调
 function then(onFulfilled, onRejected) {
  // 根据规范,如果then的参数不是function,则忽略它, 让值继续往下传递,链式调用继续往下执行
  typeof onFulfilled !== 'function' ? onFulfilled = value => value : null
  typeof onRejected !== 'function' ? onRejected = error => error : null
  // then 返回一个新的promise
  return new MyPromise((resolve, reject) => {
    const resolveFn = value => {
      try {
        const x = onFulfilled(value)
        // 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
        x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
      } catch (error) {
        reject(error)
      }
    }
  }
}
  const rejectFn = error => {
      try {
        const x = onRejected(error)
        x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
      } catch (error) {
        reject(error)
      }
    }
    switch (this._status) {
      case STATUS.PENDING:
        this._resolveQueue.push(resolveFn)
        this._rejectQueue.push(rejectFn)
        break;
      case STATUS.FULFILLED:
        resolveFn(this._value)
        break;
      case STATUS.REJECTED:
        rejectFn(this._value)
        break;
    }
 })
 }
 catch (rejectFn) {
  return this.then(undefined, rejectFn)
}
// promise.finally方法
finally(callback) {
  return this.then(value => MyPromise.resolve(callback()).then(() => value), error => {
    MyPromise.resolve(callback()).then(() => error)
  })
}
 // 静态resolve方法
 static resolve(value) {
      return value instanceof MyPromise ? value : new MyPromise(resolve => resolve(value))
  }
 // 静态reject方法
 static reject(error) {
      return new MyPromise((resolve, reject) => reject(error))
    }
 // 静态all方法
 static all(promiseArr) {
      let count = 0
      let result = []
      return new MyPromise((resolve, reject) =>       {
        if (!promiseArr.length) {
          return resolve(result)
        }
        promiseArr.forEach((p, i) => {
          MyPromise.resolve(p).then(value => {
            count++
            result[i] = value
            if (count === promiseArr.length) {
              resolve(result)
            }
          }, error => {
            reject(error)
          })
        })
      })
    }
 // 静态race方法
 static race(promiseArr) {
      return new MyPromise((resolve, reject) => {
        promiseArr.forEach(p => {
          MyPromise.resolve(p).then(value => {
            resolve(value)
          }, error => {
            reject(error)
          })
        })
      })
    }
}
相关文章
|
16天前
|
JavaScript
分享经典面试题:JS数组去重的多种方法
分享经典面试题:JS数组去重的多种方法
|
21天前
|
JavaScript 前端开发
前端面试02(JS)
本文是前端面试系列的第二篇,主要涵盖了JavaScript的基础知识,包括JS的组成(ECMAScript、DOM、BOM)、内置对象(如String、Array、Math、Date等)、数组操作方法、数据类型检测方法(typeof、instanceof、constructor、Object.prototype.toString.call)、闭包的概念及其特点、前端内存泄漏的原因和类型、事件委托的优势、基本数据类型与引用数据类型的差异、原型链的工作原理以及JS实现继承的多种方式(原型链、构造函数、组合继承等)。文章结尾鼓励读者点赞和支持作者。
12 1
|
28天前
|
前端开发 JavaScript
JavaScript新科技:PostCSS的安装和使用,2024年最新2024网易Web前端高级面试题总结
JavaScript新科技:PostCSS的安装和使用,2024年最新2024网易Web前端高级面试题总结
|
28天前
|
前端开发 JavaScript
JavaScript:this-关键字,2024中级前端开发面试解答
JavaScript:this-关键字,2024中级前端开发面试解答
|
29天前
|
JSON JavaScript 前端开发
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
|
29天前
|
JavaScript 前端开发 程序员
web前端入门到实战:32道常见的js面试题(1),面试哪些
web前端入门到实战:32道常见的js面试题(1),面试哪些
|
29天前
|
前端开发 JavaScript
web前端JS高阶面试题,2024我的前端大厂面试之旅
web前端JS高阶面试题,2024我的前端大厂面试之旅
|
29天前
|
JavaScript 前端开发
web前端JS高阶面试题(1),高级开发工程师面试
web前端JS高阶面试题(1),高级开发工程师面试
|
29天前
|
JSON 前端开发 JavaScript
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
|
29天前
|
JSON JavaScript 前端开发
【JavaScript】面试手撕深拷贝(1),面试前必看的一本书书籍是什么
【JavaScript】面试手撕深拷贝(1),面试前必看的一本书书籍是什么

热门文章

最新文章