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免费教程资源汇总

    新手快速学习JavaScript免费教程资源汇总 背景介绍 JavaScript 是一种常用的编程语言,具有广泛的应用领域。如果您是一个 JavaScript 初学者,可以通过参考多种免费的教程资源来快速掌握这门语言。在本文中,我们将分享一些值得推荐的免费 JavaScript 学习资源,帮助您在学习的过程中少走弯路。 步骤 下面是一个 JavaScript…

    JavaScript 2023年5月27日
    00
  • js replace正则相关的诡异问题

    首先,我们需要了解replace方法是用于将一个字符串中的指定字符或正则表达式替换成新的字符串。在使用replace方法时,通常会用到正则表达式来匹配需要替换的字符串。 但是,在使用replace方法时,如果我们将正则表达式中的括号与g全局标记一起使用时,容易出现一些诡异的问题。下面,我将列举两个示例来说明这个问题。 示例一: const str = ’12…

    JavaScript 2023年6月10日
    00
  • 3款实用的在线JS代码工具(国外)

    3款实用的在线JS代码工具(国外) 1. JSFiddle 简介 JSFiddle 是一个在线的代码编辑器,可以用来编辑 HTML/CSS/JavaScript 代码,并且可以立即运行和分享代码。它可以在左侧编辑 HTML/CSS/JavaScript 代码,在中间显示运行结果,在右侧显示 JavaScript 控制台。 使用方法 打开 JSFiddle 的…

    JavaScript 2023年5月19日
    00
  • iOS基于CATransition实现翻页、旋转等动画效果

    下面我将详细讲解如何使用iOS的CATransition实现翻页、旋转等动画效果。 1. 简介 iOS的CATransition动画是一种Core Animation库提供的、基于图层的动画,它可以实现一些非常酷炫的动画效果,包括翻页、旋转、淡入淡出等效果。 2. 实现方法 在iOS中,使用CATransition动画非常简单,只需要按照以下步骤操作: 2.…

    JavaScript 2023年5月28日
    00
  • countUp.js实现数字滚动效果

    下面我将详细讲解“countUp.js实现数字滚动效果”的完整攻略。 什么是countUp.js countUp.js是一个轻量级的JavaScript库,它可以帮助开发者实现数字滚动效果,使数字以动画的形式逐步增加到目标值。 应用场景 countUp.js常用于数字计数器、数据统计、商品价格展示等需要数字动态变化的场景。 使用方法 步骤一:引入countU…

    JavaScript 2023年6月11日
    00
  • javascript删除元素节点removeChild()用法实例

    JavaScript中的removeChild方法 在JavaScript中,我们可以使用removeChild方法来删除一个指定的元素节点。该方法需要根据节点的父元素来找到要删除的节点,并从它的父元素中将该节点删除。 语法 removeChild()方法的语法如下: parentElement.removeChild(childElement) 其中,pa…

    JavaScript 2023年6月10日
    00
  • JavaScript style对象与CurrentStyle对象案例详解

    让我们来讲解一下“JavaScript style对象与CurrentStyle对象案例详解”的完整攻略。 什么是style对象? 在前端开发中,style对象是经常用到的一个对象。我们可以使用style对象来获取或修改指定元素的样式属性。通过style对象,我们可以直接通过JavaScript代码来修改网页的样式效果,而无需通过css文件修改。 如何获取s…

    JavaScript 2023年5月27日
    00
  • 详解JS中的立即执行函数

    详解JS中的立即执行函数 在JS中,立即执行函数(Immediately Invoked Function Expression,IIFE)是一种常见的函数调用方式。IIFE有许多不同的应用场景,例如定义模块、创建私有作用域等。本文将详细讲解IIFE的语法和使用场景,并提供两个示例说明。 语法 IIFE的基本语法如下: (function () { // 这…

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