理解 JavaScript 中的依赖注入

2025-05-28

理解 JavaScript 中的依赖注入

依赖注入对于初学者来说是一个相当复杂的主题。了解这个概念可能并非必要,但了解它会帮助你更好地设计代码。

让我们从定义开始。
依赖注入 - 依赖注入是一种对象接收其所依赖的其他对象的技术(来源:维基百科)。

现在让我们尝试稍微分解一下这个定义。先从对象开始。对象是类的一个实例。例如

// lets define a class dog
class Dog{
  speak(){
    console.log("wuff");
  }
}

//now lets create object dog
const fluffy = new Dog();
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们有一个 Dog 类,而 Fluffy 是 Dog 类的对象。当我们新建一个类时,我们会创建该类的一个对象。这是在 JavaScript 中创建对象的方法之一(也是在 C# 和 Java 等语言中创建对象的常用方法)。
现在让我们看一个两个对象相互依赖的例子。

class Pet{
  whatDoesMyPetSay(){
    const pet = new Dog();
    pet.speak();
  }
}

const fluffy = new Pet();
fluffy.whatDoesMyPetSay();
// response will be "wuff"
Enter fullscreen mode Exit fullscreen mode

如我们所见,Pet 类依赖于 Dog 类。因此,为了达到我们想要的效果,我们需要在 Pet 类中创建一个 Dog 类的实例。现在,这个类不可重用,因为它与 Dog 类绑定在一起。如果有人把猫作为 Pet,他们将无法使用这个类。这就是所谓的紧耦合代码。
现在,让我们修改这段代码,并尝试使用依赖注入来满足所有其他宠物主人的需求。但首先,让我们创建一个猫类。

class Cat{
  speak(){
    console.log("meow");
  }
}
Enter fullscreen mode Exit fullscreen mode

cat 类也必须实现相同的方法才能使依赖注入正常工作。在 C# 和 Java 等语言中,这是通过使用接口来实现的。但 JavaScript 中没有这样的方法,所以开发者需要自己记住它。现在让我们看看 pet 类的新实现。

class Pet{
  //usually we have a private variable that needs 
  //to be accessed only in this class
  #pet;

  //create a constructor that recieves the dependent
  //object
  constructor(pet){
    this.#pet = pet;
  }

  whatDoesMyPetSay(){
    //as long as pet class implements speak method we are fine
    this.#pet.speak();
  }
}

//what does fluffy the dog say?
const fluffy = new Pet(new Dog());
fluffy.whatDoesMyPetSay();
//The response will be "wuff"

//what does milo the cat say?
const milo = new Pet(new Cat());
milo.whatDoesMyPetSay();
//The response will be "meow"
Enter fullscreen mode Exit fullscreen mode

现在,我们已经从 pet 类内部移除了依赖项,并将其交给了该类的调用者。这提升了 pet 类的可重用性。这是一个非常简单的示例,目的只是为了理解依赖注入,而不是实现它。在现实世界中,依赖项甚至会从调用者那里抽象出来,并交给一个新对象,这个新对象通常称为注入器 (Injector)。

为什么不在 JavaScript 中使用依赖注入

如果你读到这里,我希望你对依赖注入的概念更加清晰了。现在让我们看看一些我们可能不想使用依赖注入的原因。

  • 与 C# 和 Java 等纯粹基于类的语言不同,JavaScript 在功能分组方面提供了极大的灵活性。很多时候,你甚至不需要使用类,只需使用函数就足够了。在这种情况下,尝试实现依赖注入只会增加不必要的复杂性。
  • JavaScript 本质上也是动态的。你可以覆盖并使用 JavaScript 中的任何函数实现。因此,我们应该利用这些特性,而不是依赖注入来对代码进行单元测试。

归根结底,作为一名开发人员,我们应该意识到,没有一种解决方案可以解决所有问题。我希望通过本文,您能够更好地选择解决方案。

文章来源:https://dev.to/_mohanmurali/understanding-dependency-injection-in-javascript-3374
PREV
来自高级 React 开发人员的 17 条建议
NEXT
GitHub 的 8 个生产力技巧