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日

相关文章

  • JS扩展方法实例分析

    JS扩展方法实例分析 什么是JS扩展方法? JS扩展方法是指在已有的JS对象或原型上,新增一个方法,以增加该对象的功能或扩展JS的功能。 JS扩展方法的优点 可以为JS已有对象增加功能,避免手写重复代码。 可以减少变量的声明,易于维护和升级。 增强JS的灵活性和可扩展性。 JS扩展方法的实现方式 JS扩展方法可以通过为原生对象的构造函数的prototype对…

    JavaScript 2023年6月10日
    00
  • JS对象创建的几种方式整理

    JS对象创建的几种方式整理的攻略如下: 1. 对象字面量方式 对象字面量方式是指直接使用 {} 创建对象,使用键值对的方式来描述对象的属性和属性值。示例如下: const person = { name: "Alice", age: 25, sayHi: function() { console.log("Hi, I’m &qu…

    JavaScript 2023年5月27日
    00
  • ES6扩展运算符的使用方法示例

    下面是“ES6扩展运算符的使用方法示例”的完整攻略。 什么是ES6扩展运算符? ES6扩展运算符,也称为…,它可以将一个数组或对象展开成自己的元素。 使用场景 在开发中,我们经常需要用到数组或对象的合并、去重、替换等操作,ES6扩展运算符就提供了方便快捷的方式。 使用方法 1. 数组的合并 假设我们有两个数组arr1和arr2,需要将它们合并成一个新的数…

    JavaScript 2023年6月11日
    00
  • Js实现滚动变色的文字效果

    下面是“Js实现滚动变色的文字效果”完整攻略。 1. 前置知识 在介绍滚动变色的文字效果之前,我们需要了解几个前置知识: 1.1 DOM DOM(Document Object Model)是指文档对象模型,通过 DOM 可以获取 HTML 页面中的各种元素,比如文本框、按钮、下拉框等等。在 JavaScript 中,可以通过 DOM 操作来改变元素的属性、…

    JavaScript 2023年6月11日
    00
  • 关于COOKIE个数与大小的问题

    关于 COOKIE 个数与大小的问题,需要注意以下几点: 1. COOKIE 个数 每个网站可以存储的 COOKIE 数量是有限制的,不同的浏览器有不同的限制。以下是一些常见浏览器的 COOKIE 个数限制: IE 6/7: 20 IE 8/9/10/11:50 Firefox:50 Chrome:180 Safari:150 如果网站设置了超过这些限制的 …

    JavaScript 2023年6月11日
    00
  • html5将图片转换成base64的实例代码

    为了将图片转换成base64,可以使用以下步骤: 首先,将图片上传到网站服务器。这可以通过FTP或通过应用程序的文件上传功能来完成。 一旦图片上传成功,可以使用以下方法之一将其转换为base64编码: 使用在线base64编码转换工具:可以通过搜索引擎找到许多在线工具。一般情况下,这些工具只需要将图片上传到它们的服务器,然后返回base64字符串。但需要注意…

    JavaScript 2023年5月19日
    00
  • 由document.body和document.documentElement想到的

    想要使用document.body或document.documentElement,需要先了解它们的含义。 document.documentElement代表了整个HTML文档,包括标签及其下的所有内容。而document.body代表了标签及其下的所有内容。在使用document.body或document.documentElement时,可以通过它…

    JavaScript 2023年6月11日
    00
  • 使用JS+XML(数据岛)实现分页)

    那么下面就是详细讲解“使用JS+XML(数据岛)实现分页”的完整攻略: 什么是数据岛? 数据岛是一种传输XML数据的技术。通过XML数据岛技术,我们可以将XML数据作为HTML文档的一部分传输到客户端。XML数据岛把XML数据存储在一个特定的DIV元素中,在浏览器页面上隐藏该元素即可,通过JavaScript的DOM操作,即可取得数据,从而实现数据分页的需求…

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