【力扣】2704. 相等还是不相等

【力扣】2704. 相等还是不相等

文章目录

一、题目

请你编写一个名为 expect 的函数,用于帮助开发人员测试他们的代码。它应该接受任何值 val 并返回一个包含以下两个函数的对象。

  • toBe(val) 接受另一个值并在两个值相等( === )时返回 true 。如果它们不相等,则应抛出错误 "Not Equal"
  • notToBe(val) 接受另一个值并在两个值不相等( !== )时返回 true 。如果它们相等,则应抛出错误 "Equal"

示例 1:

复制代码
输入:func = () => expect(5).toBe(5)
输出:{"value": true}
解释:5 === 5 因此该表达式返回 true。

示例 2:

复制代码
输入:func = () => expect(5).toBe(null)
输出:{"error": "Not Equal"}
解释:5 !== null 因此抛出错误 "Not Equal".

示例 3:

复制代码
输入:func = () => expect(5).notToBe(null)
输出:{"value": true}
解释:5 !== null 因此该表达式返回 true.

二、解决方案

1、Expect 函数概述

本问题需要你创建一个名为expect的 JavaScript 函数,以帮助开发人员测试他们的代码。expect 函数接受任何值作为参数,并返回一个包含两个方法的对象:toBe(val) notToBe(val)

  • toBe(val) 方法接受另一个值作为参数,如果这两个值严格相等 (===) ,则返回 true,否则抛出一个带有"Not Equal"消息的错误。
  • notToBe(val) 方法接受另一个值作为参数,如果这两个值不严格相等 (!==) ,则返回 true,否则抛出一个带有"Equal"消息的错误。

要有效解决这个问题,需要对 JavaScript 的概念有较强的掌握,包括对象、函数以及严格相等和不相等运算符(=== !==)。此外,还需要了解 JavaScript 的错误处理机制,特别是throw语句。expect 函数在各种测试框架中广泛使用,以确保特定的代码段是否按预期运行。它可以帮助验证特定函数是否对给定的输入产生正确的值,或者在调用特定方法时对象的状态是否按预期改变。为了更好地理解这个概念,建议参阅有关 JavaScript 严格相等和严格不相等运算符(=== !==)以及throw语句的资料。如果你对 JavaScript 函数不太熟悉,可以查看 2667. 创建 Hello World函数 这道题。如果你想了解如何深入比较 JavaScript 中的值,推荐阅读 2628. 完全相等的 JSON 字符串 这道题。

(1)JavaScript 对象和函数返回

在 JavaScript 中,函数可以返回对象,对象是相关数据和函数(通常称为属性和方法)的集合。

以下是一个返回对象的函数示例:

javascript 复制代码
function createPerson(name, age) {
  return {
    name: name,
    age: age,
    greet: function() {
      console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
    }
  };
}

let person = createPerson("Alice", 25);
person.greet(); // "Hello, my name is Alice and I'm 25 years old."

在 JavaScript 中,特别是处理对象时,this 关键字的使用是一个基本概念。如果你想要深入了解关于 JavaScript 的这一重要内容,强烈推荐尝试我们的 2619.数组原型对象的最后一个元素 这道题。

(2)JavaScript 对象和有限方法链

JavaScript 对象是一种重要的结构,用于将相关数据和函数组合在一起。它们可以容纳包括函数在内的各种数据类型,当函数位于对象内部时,就被视为对象的方法。

在当前的问题中,expect 函数返回一个对象。该对象包含toBenotToBe方法。尽管这些方法可以以类似链式的方式连续调用,但这代表了一种受限制的方法链,因为它们不会返回原始对象以供进一步链式调用,而这正是 JavaScript 编程中方法链的一个关键特征。

全方法链是 JavaScript 中的常见模式,允许在单个语句中调用多个方法。此模式是通过每个方法返回一个对象来实现的,该对象可以是原始对象(对于可变对象)或新对象(对于不可变对象)。全方法链提高了代码的可读性和简洁性,在许多 JavaScript 库中都是首选的模式。

以下是完整方法链的示例:

javascript 复制代码
let arr = [5, 2, 8, 1];

let result = arr.sort().reverse().join("-");

console.log(result); // "8-5-2-1"

在此示例中,sort() 方法对数组进行排序,然后reverse()方法反转排序后的数组,最后join("-")方法将元素连接成一个以「-」为分隔符的字符串。每个方法都返回一个数组,允许直接在结果上调用下一个方法。

expect函数的上下文中,方法链的一种受限形式允许开发人员在单行中无缝使用toBenotToBe方法,如下所示:

javascript 复制代码
expect(5).toBe(5); // 返回 true 或抛出错误
expect(5).notToBe(3); // 返回 true 或抛出错误

expect 函数返回一个包含toBe notToBe方法的对象。这些方法不会返回原始对象,而是返回 true 或根据比较结果抛出错误。因此,expect 函数提供了一种受限制的方法链;尽管如此,它在许多情况下仍然非常有用。

(3)JavaScript 错误处理

在 JavaScript 中,错误处理主要通过使用throw语句和try...catch块来实现。使用throw语句允许你创建自定义错误消息,这对于调试代码非常有用。根据你想要实现的目标,可以使用不同的方式使用throw语句。

1)抛出字符串:

你可以在 JavaScript 中抛出一个字符串。它将在catch块中被捕获为错误消息。

javascript 复制代码
function checkName(name) {
  if (name === '') {
    throw "Name can't be empty!";
  }
  return name;
}

try {
  console.log(checkName(''));
} catch (error) {
  console.error(error); // "Name can't be empty!"
}
2)抛出 Error 实例:

一种更常见和推荐的方法是抛出一个Error实例。这允许在错误中包含比如堆栈跟踪的附加元数据,有助于调试。

javascript 复制代码
function divide(numerator, denominator) {
  if (denominator === 0) {
    throw new Error("Cannot divide by zero!");
  }
  return numerator / denominator;
}

try {
  console.log(divide(5, 0));
} catch (error) {
  console.error(error.message); // "Cannot divide by zero!"
}
3)抛出聚合错误:

有时候,你可能希望同时抛出多个错误。这在处理Promise时特别有用。JavaScript 有一个内置的AggregateError对象,可以在这类情况下使用。AggregateError 对象可以接受一个错误对象的可迭代集合和一个可选的消息作为参数。

javascript 复制代码
let error1 = new Error("First Error");
let error2 = new Error("Second Error");

try {
  throw new AggregateError([error1, error2], "Two errors occurred.");
} catch (error) {
  if (error instanceof AggregateError) {
    console.error(error.message); // "Two errors occurred."
    for (let e of error.errors) {
      console.error(e.message); // 打印 "First Error" 和 "Second Error"
    }
  }
}

方法 1:对象工厂

(1)概述

在这个问题中,我们被要求实现一个名为expect的函数,用于对代码执行一些基本的测试。该函数应该接受任何值,并返回一个包含两个方法的对象:toBe notToBe

toBe 方法应该接受另一个值,并使用严格相等运算符(===) 将这两个值进行比较,如果它们严格相等 (===),则返回 true。如果它们不相等,则应抛出一个带有"Not Equal"消息的错误。

同样,notToBe 方法应该接受另一个值,并使用严格不相等运算符 (!==) 将这两个值进行比较,如果它们不完全相等 (!==) ,则返回 true。如果它们相等,则应抛出一个带有"Equal"消息的错误。

(2)算法
  1. expect返回一个包含toBenotToBe方法的对象。
  2. toBe方法中,将输入值与传递给expect的值进行比较。如果它们相等,返回 true。如果不相等,则抛出一个带有 「Not Equal」 消息的错误。
  3. 类似地,在notToBe方法中,将输入值与传递给expect的值进行比较。如果它们不相等,返回 true。如果它们相等,则抛出一个带有「Equal」消息的错误。
(3)实现

这个解决方案可以通过给定的函数表达式或构造一个额外的 ES6 类来实现。

实现 1:函数表达式

在这个实现中,expect 函数充当工厂函数,创建一个包含toBenotToBe两个方法的对象。这两个方法分别使用严格相等 ( === ) 或不等 ( !== ) 运算符将val与传递给expect的值进行比较,根据比较的结果返回true或抛出错误。

javascript 复制代码
var expect = function(val) {
  return {
    toBe: (val2) => {
      if(val !== val2) throw new Error("Not Equal");
      return true;
    },
    notToBe: (val2) => {
      if(val === val2) throw new Error("Equal");
      return true;
    }
  };
};
javascript 复制代码
type ToBeOrNotToBe = {
  toBe: (val: any) => boolean;
  notToBe: (val: any) => boolean;
};

const expect = (val: any): ToBeOrNotToBe => {
    return {
        toBe: (val2: any): boolean => {
            if(val !== val2) throw new Error("Not Equal");
            return true;
        },
        notToBe: (val2: any): boolean => {
            if(val === val2) throw new Error("Equal");
            return true;
        }
    };
};
实现 2:使用 ES6 类

在这个代码中,expect 是一个函数,返回一个新的Expect类的实例。该实例保留传递给expect的值,并在其toBenotToBe 方法中使用该值。

javascript 复制代码
class Expect {
  constructor(val) {
    this.value = val;
  }

  toBe(compareVal) {
    if (this.value !== compareVal) {
      throw new Error("Not Equal");
    }
    return true;
  }

  notToBe(compareVal) {
    if (this.value === compareVal) {
      throw new Error("Equal");
    }
    return true;
  }
}

function expect(val) {
  return new Expect(val);
}
javascript 复制代码
class Expect<T> {
    private val: T;

    constructor(val: T) {
        this.val = val;
    }
    
    toBe(val2: T): boolean {
        if (this.val !== val2) {
            throw new Error("Not Equal");
        }
        return true;
    }
    
    notToBe(val2: T): boolean {
        if (this.val === val2) {
            throw new Error("Equal");
        }
        return true;
    }
}

function expect<T>(val: T): Expect<T> {
    return new Expect(val);
}
(4)复杂性分析

时间复杂度:O(1),函数只创建一个包含两个方法的对象,不执行任何迭代或递归操作。

空间复杂度:O(1),函数始终创建一个包含两个方法的对象,不管输入值的大小或复杂性如何。因此,函数使用的内存量不会随着输入大小而变化,导致常数空间复杂度。

(5)面试技巧:
  • JavaScript 中函数返回对象或其他函数是什么意思?

    当一个函数返回对象或其他函数时,它使用了高阶函数和工厂函数。高阶函数是通过接受其他函数作为参数或返回它们来操作其他函数的函数。另一方面,工厂函数是返回对象实例的函数。这个概念在函数式编程中非常重要,提供了一种封装和重用代码的方式。

  • 方法链在 JavaScript 中是如何工作的,什么时候使用它可能会更有效?

    方法链是 JavaScript 中常见的一种模式,允许在单个语句中调用多个方法。这是因为每个方法返回一个对象,该对象可以是原始对象(对于可变对象)或新对象(对于不可变对象)。方法链使代码更易读和简洁,在执行多个转换或操作时特别有用。

  • 在 JavaScript 中,== ===有什么区别?

    == 运算符是抽象相等运算符,如果两个变量的类型不同,它将尝试进行类型转换。另一方面,=== 运算符是严格相等运算符,不进行类型转换,仅在两个变量的值和类型都相同时返回 true

  • 如何在 JavaScript 函数中处理错误?

    在 JavaScript 函数中处理错误可以通过使用try...catch...finally块来实现。try 块包含可能引发错误的代码,catch 块在try块中发生错误时执行,finally 块在 trycatch块之后始终执行,无论结果如何。另一种处理错误的方式是使用错误优先的回调,这是Node.js中常见的模式,其中回调函数的第一个参数保留给错误对象。

  • 为什么我们要抛出错误,而不是在toBenotToBe方法中直接返回 false

    抛出错误可以提供更多关于出错原因的信息,并允许你在代码的更高层使用 try...catch语句捕获错误。相比之下,简单地返回false只会告诉你值不相等,而不会提供任何进一步的上下文或信息。

相关推荐
TL滕20 小时前
从0开始学算法——第十九天(并查集练习)
笔记·学习·算法
im_AMBER20 小时前
Leetcode 80 统计一个数组中好对子的数目
数据结构·c++·笔记·学习·算法·leetcode
少许极端20 小时前
算法奇妙屋(十九)-子序列问题(动态规划)
java·数据结构·算法·动态规划·子序列问题
咬人喵喵20 小时前
CSS Flexbox:拥有魔法的排版盒子
前端·css
LYFlied20 小时前
TS-Loader 源码解析与自定义 Webpack Loader 开发指南
前端·webpack·node.js·编译·打包
yzp011220 小时前
css收集
前端·css
暴富的Tdy20 小时前
【Webpack 的核心应用场景】
前端·webpack·node.js
遇见很ok20 小时前
Web Worker
前端·javascript·vue.js
elangyipi12320 小时前
JavaScript 高级错误处理与 Chrome 调试艺术
开发语言·javascript·chrome
风舞红枫20 小时前
前端可配置权限规则案例
前端