Heim  >  Artikel  >  Web-Frontend  >  Ich wusste nicht, dass Sie Geschwisterparameter als Standardwerte in Funktionen verwenden können.

Ich wusste nicht, dass Sie Geschwisterparameter als Standardwerte in Funktionen verwenden können.

Linda Hamilton
Linda HamiltonOriginal
2024-10-13 06:24:30305Durchsuche

I didn

JavaScript unterstützt seit ES2015 Standardparameterwerte. Das wissen Sie. Ich weiß das. Was ich nicht wusste, war, dass Sie Geschwister Parameter als Standardwerte selbst verwenden können. (Oder vielleicht „benachbarte Positionsparameter“? Ich bin mir nicht sicher, wie ich diese nennen soll.)

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

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

Dies funktioniert auch in Klassenkonstruktoren – etwas, das ich als sehr hilfreich empfunden habe, um PicPerf.io-Code besser testbar zu machen. Zu diesem Zweck wird häufig eine einfache Abhängigkeitsinjektion eingesetzt. Lass es uns ein wenig erkunden.

Ein Szenario

Um beim Bildoptimierungsthema zu bleiben, sagen wir, Sie haben eine OptimizedImage-Klasse. Geben Sie dem Konstruktor eine Bild-URL an, und Sie können entweder einen frisch optimierten Puffer des Bildes oder eine zwischengespeicherte Version abrufen.

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();

Der einzige in der Produktion verwendete Konstruktorparameter ist imageUrl, aber das Einfügen von CacheService und OptimizeService ermöglicht einen einfacheren Unit-Test mit Mocks:

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'
  );
});

Das macht es noch komplizierter

In diesem Beispiel verwenden beide Serviceklassen imageUrl nur, wenn bestimmte Methoden aufgerufen werden. Aber stellen Sie sich vor, sie müssten es stattdessen an ihre eigenen Konstruktoren übergeben. Sie könnten versucht sein, die Instanziierung in den Konstruktor von OptimizedImage zu ziehen (das war ich):

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

Das würde funktionieren, aber jetzt ist OptimizedImage vollständig für die Dienstinstanziierung verantwortlich, und auch das Testen wird zu einem größeren Aufwand. Es ist nicht so einfach, Mocks für Serviceinstanzen zu übergeben.

Sie könnten dies umgehen, indem Sie Scheinklassendefinitionen übergeben, aber Sie müssten dann Scheinversionen dieser Klassen mit ihren eigenen Konstruktoren erstellen, was das Testen mühsamer macht. Glücklicherweise gibt es eine andere Möglichkeit: Verwenden Sie den Parameter imageUrl im Rest Ihrer Argumentliste.

Geschwisterparameter teilen

Ich wusste bis vor einiger Zeit nicht, dass das überhaupt möglich ist. So würde es aussehen:

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);
  }
}

Mit diesem Setup können Sie diese Instanzen genauso einfach verspotten wie zuvor, und der Rest der Klasse muss nicht einmal eine Instanz von imageUrl selbst festhalten. Die Instanziierung bleibt natürlich weiterhin einfach:

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

const img = await instance.get();

Derselbe Testansatz bleibt ebenfalls bestehen:

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');
});

Hier gibt es nichts Bahnbrechendes – nur eine kleine Funktion, die mein Leben ergonomisch etwas angenehmer gemacht hat. Ich hoffe, in Zukunft noch mehr Juwelen wie dieses zu finden.

Das obige ist der detaillierte Inhalt vonIch wusste nicht, dass Sie Geschwisterparameter als Standardwerte in Funktionen verwenden können.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn