JavaScript常见手写题超全汇总

JavaScript常见手写题超全汇总

1. 前言

在面试以及实际工作中,常常需要手写一些核心的JavaScript代码。这些手写题目可能比较简单、或者非常复杂,但是它们都对JavaScript基础功夫有一个更加深刻的理解。

在本篇文章中,我们将会汇总一些常见的JavaScript手写题,包括但不限于:数组去重、深拷贝、Promise实现、函数柯里化等等。

2. 数组去重

数组去重是一个非常基础的手写题,着重考察了对JavaScript基本数据类型以及数据结构的理解。以下是一些常见的去重方法:

方法一: Set

通过Set将数组转换成为一个集合,然后将集合转换成为数组即可。

function uniqueArray(arr) {
  return Array.from(new Set(arr));
}

方法二: for循环 + indexOf

遍历数组,用indexOf判断数组中是否已经存在当前元素,如果不存在则push进新数组中。

function uniqueArray(arr) {
  let newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}

3. 深拷贝

JavaScript中的对象和数组都是引用类型,如果直接赋值只是复制了引用地址,两个变量指向的是同一个地址。因此,深拷贝是非常重要的操作。

方法一: JSON.parse 和 JSON.stringify

使用JSON.parse将对象转成字符串,再使用JSON.stringify将字符串转成对象实现深拷贝。

function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

注意:这种方法虽然简单,但是会忽略undefined、function、symbol等属性及嵌套层数大于等于1000的对象。

方法二: 递归

使用递归实现深拷贝。递归思路:判断参数是否是数组或对象,是的话就新建一个数组或对象,继续遍历并赋值。

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  let newObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    newObj[key] = deepClone(obj[key]);
  }
  return newObj;
}

4. Promise实现

Promise是ES6中的一个新特性,它通过解决回调地狱的问题,让异步操作更加方便和可读。

方法一: Promise构造函数

使用Promise构造函数来实现Promise。通过函数传递resolve、reject函数,并在异步操作完毕时调用相应的函数。

function myPromise(fn) {
  let state = "pending";
  let value = null;
  let callbacks = [];
  const resolve = function (newValue) {
    if (state === "pending") {
      state = "fulfilled";
      value = newValue;
      callbacks.forEach((callback) => callback.onFulfilled(value));
    }
  };
  const reject = function (newValue) {
    if (state === "pending") {
      state = "rejected";
      value = newValue;
      callbacks.forEach((callback) => callback.onRejected(value));
    }
  };
  this.then = function (onFulfilled, onRejected) {
    return new myPromise((resolve, reject) => {
      if (state === "pending") {
        callbacks.push({
          onFulfilled: (value) => {
            try {
              if (typeof onFulfilled === "function") {
                const result = onFulfilled(value);
                resolve(result);
              } else {
                resolve(value);
              }
            } catch (err) {
              reject(err);
            }
          },
          onRejected: (value) => {
            try {
              if (typeof onRejected === "function") {
                const result = onRejected(value);
                reject(result);
              } else {
                reject(value);
              }
            } catch (err) {
              reject(err);
            }
          },
        });
      }
      if (state === "fulfilled") {
        try {
          if (typeof onFulfilled === "function") {
            const result = onFulfilled(value);
            resolve(result);
          } else {
            resolve(value);
          }
        } catch (err) {
          reject(err);
        }
      }
      if (state === "rejected") {
        try {
          if (typeof onRejected === "function") {
            const result = onRejected(value);
            reject(result);
          } else {
            reject(value);
          }
        } catch (err) {
          reject(err);
        }
      }
    });
  };
  fn(resolve, reject);
}

注意: 这种方法虽然可以实现Promise实例,但是没有考虑异步,因此我们在实现时需要将异步操作放到setTimeout中。

方法二:Async/Await搭配Generator

使用Async/Await搭配Generator来实现Promise。在编写异步操作时,使用Generator的语法报告异步上下文,然后通过Async/Await来异步等待,实现同步式编码。

function myPromise(fn) {
  let value = null;
  let resolved = false;
  let fnGenerator = function* () {
    yield new Promise((resolve, reject) => {
      const resolveWrap = (res) => {
        value = res;
        resolved = true;
        resolve(res);
      };
      const rejectWrap = (res) => {
        value = res;
        resolved = true;
        reject(res);
      };
      fn(resolveWrap, rejectWrap);
    });
  };
  this.then = async function (cb) {
    const result = await fnGenerator().next().value;
    return cb(result);
  };
}

5. 函数柯里化

函数柯里化是指将一个多参数的函数,转化为一个嵌套的单参数函数的技术。

以下是一些常见的函数柯里化方法:

方法一:反向柯里化

按照参数列表的最后一项先生成闭包,然后通过嵌套函数生成环境,最后在外层return内层的函数。

function curry(fn) {
  const length = fn.length;
  return function curryed(...args) {
    if (args.length >= length) {
      return fn.apply(null, args);
    } else {
      return function () {
        const allArgs = [...args, ...arguments];
        return curryed.apply(null, allArgs);
      };
    }
  };
}

方法二:正向柯里化

又称纯函数柯里化,被称为"curry"的函数,是指能够把一个N元函数转换成N个一元函数的方法。函数柯里化的主要作用是将数据转换成为适合函数操作的形式。

function add(a, b, c) {
  return a + b + c;
}

function curryedAdd(a) {
  return function (b) {
    return function (c) {
      return add(a, b, c);
    };
  };
}

const result = curryedAdd(1)(2)(3);
console.log(result); //6

6. 结语

本文仅对手写题目进行了简单的介绍,对于每道题目都有更多实现方式,读者可以自行拓展。

但是需要指出的是,重点并不在于知道怎么写,而是能够思考出不同的解决方式,举一反三。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript常见手写题超全汇总 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • JavaScript字符串处理(String对象)详解

    JavaScript字符串处理(String对象)详解 在JavaScript中,字符串也是一个重要的数据类型。String对象中提供了一系列的方法来对字符串进行处理。本篇攻略将详细讲解JavaScript中String对象的常用方法。 字符串的定义 在JavaScript中,字符串可以用单引号或双引号来定义。例如: var str1 = ‘hello wo…

    JavaScript 2023年5月19日
    00
  • js中常用的Math方法总结

    JS中常用的Math方法总结 Math对象是JavaScript中的内置对象之一,它提供了许多数学函数和常量。通过Math对象,我们可以轻松地实现各种数学运算。 本攻略将会介绍JS中常用的Math方法,包括: Math.abs() Math.ceil() Math.floor() Math.max() Math.min() Math.pow() Math.r…

    JavaScript 2023年5月27日
    00
  • JavaScript实现网络测速的方法详解

    JavaScript实现网络测速的方法详解 什么是网络测速 网络测速,顾名思义就是测量网络的速度,即数据在网络中传输的速度。对于用户来说,网络速度的快慢直接会影响到用户体验,因此网络测速也成为了一个重要的测试方法。 JavaScript实现网络测速的方法 使用XMLHttpRequest XMLHttpRequest是JavaScript内置的对象,可以用来…

    JavaScript 2023年5月28日
    00
  • Javascript获取数组中的最大值和最小值的方法汇总

    下面我来详细讲解一下“Javascript获取数组中的最大值和最小值的方法汇总”。 1. Math对象函数法 我们可以使用Math对象提供的max和min函数,来获取数组中的最大值和最小值: var arr = [1, 2, 3, 4, 5]; var max = Math.max.apply(null, arr); var min = Math.min.a…

    JavaScript 2023年5月27日
    00
  • JS获取url参数、主域名的方法实例分析

    JS获取URL参数的方法实例分析 在前端开发中,经常需要获取URL中的参数,以便进行相应的逻辑处理。下面我们将介绍JS获取URL参数的方法。 方法一:正则表达式获取 常见的方法是通过正则表达式获取。 /** * @description 通过正则表达式获取URL中指定参数的值 * @param {string} name 参数名 * @param {stri…

    JavaScript 2023年5月28日
    00
  • javascript怎么禁用浏览器后退按钮

    当我们在开发 Web 应用时,可能需要在某些情况下禁用浏览器的后退按钮,以避免用户在单击后退按钮后意外离开应用或导致混乱。下面是禁用浏览器后退按钮的方法: 使用历史 API 我们可以使用历史 API,在浏览器历史记录中添加一条新的记录,这样单击后退按钮时,浏览器不会后退到上一个页面。 // 禁用浏览器后退按钮 history.pushState(null, …

    JavaScript 2023年6月11日
    00
  • JS使用setInterval实现的简单计时器功能示例

    下面是使用setInterval实现简单计时器功能的完整攻略: 简介 在项目开发中,我们经常需要实现一些计时器的功能,比如倒计时、定时更新等。而JavaScript提供了setInterval()函数,可以方便地实现计时器的功能。下面将介绍如何使用setInterval()函数实现简单计时器功能示例。 基本语法 setInterval()函数的基本语法如下:…

    JavaScript 2023年5月27日
    00
  • JavaScript jquery及AJAX小结

    JavaScript jQuery及 AJAX小结 在对于 JavaScript、jQuery 和 AJAX 进行学习和使用时,可以以下这些知识点为核心来掌握。 JavaScript 基础语法 JavaScript 可以定义变量,条件语句(if…else…)、循环语句(for、while)、函数、对象等。 下面是定义一个变量并在控制台输出的示例代码:…

    JavaScript 2023年5月18日
    00
合作推广
合作推广
分享本页
返回顶部