Maison  >  Article  >  interface Web  >  Je ne savais pas que vous pouviez utiliser des paramètres frères comme valeurs par défaut dans les fonctions.

Je ne savais pas que vous pouviez utiliser des paramètres frères comme valeurs par défaut dans les fonctions.

Linda Hamilton
Linda Hamiltonoriginal
2024-10-13 06:24:30303parcourir

I didn

JavaScript prend en charge les valeurs de paramètres par défaut depuis ES2015. Vous le savez. Je le sais. Ce que je ne savais pas, c'est que vous pouvez utiliser frère paramètres comme valeurs par défaut elles-mêmes. (Ou peut-être des « paramètres de position adjacents » ? Vous ne savez pas comment les appeler.)

function myFunc(arg1, arg2 = arg1) {
  console.log(arg1, arg2);
}

myFunc("arg1!");
// "arg1!" "arg1!"

Cela fonctionne également dans les constructeurs de classes – quelque chose que j'ai trouvé très utile pour rendre certains codes PicPerf.io plus testables. Il est courant de voir une simple injection de dépendances utilisée à cette fin. Explorons-le un peu.

Un scénario

En gardant le thème d'optimisation d'image, disons que vous avez une classe OptimizedImage. Fournissez une URL d'image à son constructeur et vous pourrez récupérer soit un tampon fraîchement optimisé de l'image, soit une version mise en cache.

class OptimizedImage {
  constructor(
    imageUrl: string,
    cacheService = new CacheService(),
    optimizeService = new OptimizeService()
  ) {
    this.imageUrl = imageUrl;
    this.cacheService = cacheService;
    this.optimizeService = optimizeService;
  }

  async get() {
    const cached = this.cacheService.get(this.imageUrl);

    // Return the previously optimized image.
    if (cached) return cached;

    const optimizedImage = await this.optimizeService
      .optimize(this.imageUrl);

    // Cache the optimized image for next time.
    return this.cacheService.put(this.imageUrl, optimizedImage);
  }
}

const instance = new OptimizedImage('https://macarthur.me/me.jpg');
const imgBuffer = await instance.get();

Le seul paramètre de constructeur utilisé en production est imageUrl, mais l'injection de CacheService et OptimizeService permet de réaliser des tests unitaires plus faciles avec des simulations :

import { it, expect, vi } from 'vitest';
import { OptimizedImage } from './main';

it('returns freshly optimized image', async function () {
  const fakeImageBuffer = new ArrayBuffer('image!');
  const mockCacheService = {
    get: (url) => null,
    put: vi.fn().mockResolvedValue(fakeImageBuffer),
  };

  const mockOptimizeService = {
    optimize: (url) => fakeImageBuffer,
  };

  const optimizedImage = new OptimizedImage(
    'https://test.jpg',
    mockCacheService,
    mockOptimizeService
  );

  const result = await optimizedImage.get();

  expect(result).toEqual(fakeImageBuffer);
  expect(mockCacheService.put).toHaveBeenCalledWith(
    'https://test.jpg',
    'optimized image'
  );
});

Rendre les choses plus compliquées

Dans cet exemple, ces deux classes de service utilisent imageUrl uniquement lorsque des méthodes particulières sont invoquées. Mais imaginez s’ils exigeaient qu’il soit transmis à leurs propres constructeurs. Vous pourriez être tenté d'intégrer l'instanciation dans le constructeur d'OptimizedImage (j'étais) :

class OptimizedImage {
  constructor(
    imageUrl: string
  ) {
    this.imageUrl = imageUrl;
    this.cacheService = new CacheService(imageUrl);
    this.optimizeService = new OptimizeService(imageUrl);
  }

Cela fonctionnerait, mais désormais OptimizedImage est entièrement responsable de l'instanciation du service, et les tests deviennent également plus compliqués. Ce n'est pas si facile de transmettre des simulations pour des instances de service.

Vous pouvez contourner ce problème en transmettant des définitions de classes fictives, mais vous devrez alors créer des versions fictives de ces classes avec leurs propres constructeurs, ce qui rend les tests plus fastidieux. Heureusement, il existe une autre option : utilisez le paramètre imageUrl dans le reste de votre liste d'arguments.

Partager les paramètres des frères et sœurs

Je ne savais même pas que cela était possible jusqu'à il y a peu de temps. Voici à quoi cela ressemblerait :

export class OptimizedImage {
  constructor(
    imageUrl: string,
    // Use the same `imageUrl` in both dependencies.
    cacheService = new CacheService(imageUrl),
    optimizeService = new OptimizeService(imageUrl)
  ) {
    this.cacheService = cacheService;
    this.optimizeService = optimizeService;
  }

  async get() {
    const cached = this.cacheService.get();

    // Return the previously optimized image.
    if (cached) return cached;

    const optimizedImage = await this.optimizeService.optimize();

    // Cache the optimized image for next time.
    return this.cacheService.put(optimizedImage);
  }
}

Avec cette configuration, vous pouvez vous moquer de ces instances aussi facilement qu'avant, et le reste de la classe n'a même pas besoin de conserver une instance de imageUrl elle-même. L’instanciation, bien sûr, reste simple :

const instance = new OptimizedImage('https://macarthur.me/me.jpg');

const img = await instance.get();

La même approche de test reste également intacte :

import { it, expect, vi } from 'vitest';
import { OptimizedImage } from './main';

it('returns freshly optimized image', async function () {
  const mockCacheService = {
    get: () => null,
    put: vi.fn().mockResolvedValue('optimized image'),
  };

  const mockOptimizeService = {
    optimize: () => 'optimized image',
  };

  const optimizedImage = new OptimizedImage(
    'https://test.jpg',
    mockCacheService,
    mockOptimizeService
  );

  const result = await optimizedImage.get();

  expect(result).toEqual('optimized image');
  expect(mockCacheService.put).toHaveBeenCalledWith('optimized image');
});

Rien de révolutionnaire ici – juste une petite fonctionnalité qui a rendu ma vie un peu plus agréable sur le plan ergonomique. J'espère rencontrer d'autres joyaux comme celui-ci à l'avenir.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn