2
votes

L'écriture d'une classe JavaScript dans laquelle une seule méthode peut à la fois obtenir et définir une propriété est-elle une mauvaise pratique?

J'écris des classes pour un jeu et je ne sais pas si l'écriture d'une classe JavaScript dans laquelle ses méthodes peuvent être utilisées pour définir ou récupérer l'un de ses membres de classes est une bonne pratique. J'essaie de comprendre pourquoi ou pas.

J'ai déjà implémenté ceci sur jsfiddle, également publié à l'adresse:

https://jsfiddle.net/97g16hq3/7/

Plus précisément, les méthodes x (x = null) et y (y = null) sont ceux auxquels je fais référence.

class Vector {
    constructor( x, y ) {
    this._x = x
    this._y = y
  }

  x(x = null) {
    if (x) {
        this._x = x
    } else {
        return this._x
    }
  }

  y(y = null) {
    if (y) {
        this._y = y
    } else {
        return this._y
    }
  }

}

const myVec = new Vector( 1, 2 )

console.log(myVec)

// Get the vector
console.log('x: ', myVec.x())
console.log('y: ', myVec.y())

// Set the vector
myVec.x(3)
myVec.y(4)

// Get the vector
console.log('new vector')
console.log('x: ', myVec.x())
console.log('y: ', myVec.y())


3 commentaires

Si vous posez des questions spécifiquement sur l'obtention / la configuration, je préfère utiliser les propriétés getter / setter au lieu des méthodes standard. De cette façon, la syntaxe du site "appel" indique clairement ce qui se passe.


@BhojendraRauniyar J'ai déjà répondu à votre message. Amunium vous a déjà expliqué correctement ce que j'allais faire


Dans votre code actuel, vous ne pouvez pas définir x sur 0 (ou sur une chaîne vide, ce qui est moins pertinent). Vous devez utiliser if (x == null) pour vérifier null ou undefined et vous ne pouvez pas définir x < / code> à null ou indéfini (peut-être que c'est correct dans votre cas). Quoi qu'il en soit, les méthodes getX () et setX (x) ou le langage intégré aux fonctions get et set sont plus lisibles.


4 Réponses :


0
votes

Cela ne signifie pas que vous attribuez la valeur:

if(x===null){

Donc, cela définit la valeur de l'argument x sur null code > si vous ne transmettez aucune valeur ou non défini.

Vérifiez paramètres par défaut pour référence.

Modifier:

Cela compte pour vos besoins. Ce qui suit définit la nouvelle valeur si elle a une valeur:

this._x = x // may result in `null`, `undefined`, ...

Mais cela définira la valeur et ne se soucie pas si elle est null , undefined ou autre chose:

if (x) {
  this._x = x
} else {
  return this._x
}

Mais il est vraiment inutile de définir la valeur par défaut pour x: x = null . Parce que vous ne faites que le vérifier avec if(x){.

Dans certains cas, vous pouvez particulièrement vérifier null et dans ce cas définir la valeur par défaut de x serait un moyen d'aller avec:

x(x = null) { // it's default value for x is null


8 commentaires

Il ne l'attribue pas dans cette ligne, non - mais regardez deux lignes vers le bas, et il est en train de définir la valeur. Il n'y a rien de mal avec le code, il demande simplement si c'est une bonne pratique.


@Amunium OP est confus s'il attribue le x comme if (x = 3) { attribue une valeur x. Mais en fait, ce n'est pas une affectation.


Et OP devrait savoir si c'est une bonne pratique ou non en utilisant la valeur par défaut null plutôt que undefined . - Surtout l'opinion.


Non, ce n'est pas du tout sa question, et rien n'indique qu'il est confus à ce sujet. Cela fonctionne bien comme ça. C'est un peu inutile en Javascript, car vous pouvez simplement tester pour undefined à la place, mais il n'y a rien de mal à cela et vous ne répondez pas à la question.


Voir cette déclaration Plus précisément, les méthodes x (x = null) et y (y = null) sont celles auxquelles je fais référence.


Oui, les méthodes . Pas les lignes, les méthodes .


Hmm, j'attendrai la réponse d'OP si je ne réponds pas à la requête d'OP ou non. Mais ce que vous dites est de définir la valeur this._x = x est un comportement normal. Je ne pense pas qu'OP pose des questions à ce sujet.


L'OP demande si c'est une bonne pratique de surcharger une seule méthode avec un comportement différent en fonction du nombre (ou du type) d'arguments passés. Ils savent déjà clairement comment le code fonctionne.



1
votes

Si vous posez des questions spécifiquement sur l'obtention / la configuration, alors je préfère utiliser les propriétés getter / setter au lieu de méthodes standard surchargées avec un comportement alternatif. De cette façon, la syntaxe du site "appel" indique clairement ce qui se passe.

class Vector {
    constructor( x, y ) {
    this._x = x
    this._y = y
  }

  get x() {
    return this._x
  }
  set x(x) {
    this._x = x
  }
  get y() {
    return this._y
  }
  set y(y) {
    this._y = y
  }
}

const myVec = new Vector( 1, 2 )

console.log(myVec)

// Get the vector
console.log('x: ', myVec.x)
console.log('y: ', myVec.y)

// Set the vector
myVec.x = 3
myVec.y = 4

// Get the vector
console.log('new vector')
console.log('x: ', myVec.x)
console.log('y: ', myVec.y)

En général, j'éviterais ce genre de comportement surchargé, surtout si le comportement diffère énormément. Cela ajoute de la confusion à une API. OMI, le nom de la méthode doit décrire ce qui se passe.


9 commentaires

C'est une excellente solution, même si je suppose que je ne suis pas sûr que cela réponde entièrement à ma question de savoir si la surcharge d'une fonction comme celle du PO est une bonne pratique ou non.


@nootdev: les "bonnes pratiques" sont toujours une question d'opinion. Je l'ai abordé plus spécifiquement au bas de la réponse.


Je crois que vous avez raison d’y penser un peu plus. Dans ce contexte, les fonctions ES natives doivent être considérées comme la meilleure pratique par rapport à l'implémentation de quelque chose de différent.


@ziggywiggy Les «bonnes pratiques» sont toujours une question d’opinion . Pas vraiment. Les mauvaises pratiques visent à éviter les problèmes de performances, les anti-modèles et les futurs problèmes de conformité. Vous parlez de style de codage. Oui je suis d'accord, c'est une question d'opinion. Mais ici je ne vois pas de mauvaise pratique.


Étant donné que la fonctionnalité existe, et en supposant que l'ancien support ES3 n'est pas une exigence, je pense que oui. Cependant en fonction des effets secondaires introduits par les getter / setters, certains auraient un argument valide pour dire que cela ne devrait pas être fait. Par exemple, object.foo = "bar" , ne devrait vraiment pas faire plus que l'affectation. S'il effectuait des calculs longs et lents, ou s'il avait des effets secondaires apparaissant à l'extérieur de l'objet, je dirais qu'il y aurait là un bon argument pour une mauvaise conception.


@LucaFagioli: "Bad practice" est la lettre écarlate de la programmation. C'est un stigmate qui permet aux codeurs d'écarter la raison. Il y a eu des notions largement répandues de «bonnes / mauvaises pratiques», fondées sur peu de mérite. Même lorsqu'ils y réfléchissent, les gens peuvent toujours être en désaccord, car différentes notions de ce qui est finalement important peuvent les motiver.


Soyons clairs: personnellement, je trouve cette approche horrible et je ne l'utiliserais pas. Je pense que nous avons trouvé des raisons raisonnables pour lesquelles utiliser get and set est une meilleure idée, mais je n'appellerais pas cela une mauvaise pratique, c'est ce que je veux dire.


@LucaFagioli: Oui, je ne l'appellerais pas «mauvais» non plus, et je ne l'utiliserais pas non plus. Les «pratiques éclairées» sont globalement les meilleures, même lorsque la majorité peut être en désaccord avec certaines d'entre elles.


@ziggywiggy En effet, c'est ce que l'OP demandait: si c'était "mauvais" ou pas. Je suis content qu'il / elle ait eu une bonne réponse.



1
votes

Mieux vaut aller standard et utiliser get et set .

Parmi les autres raisons, les IDE sont basés sur des standards pour beaucoup de leurs helpers (complétion de code, astuces ...), il vaut donc mieux en profiter.

Techniquement parlant, rien ne va pas avec votre approche. jQuery l'utilise largement: .val () , . text () , .height () ne sont qu'un exemple.

La bibliothèque existe depuis des lustres et pour autant que je sache, personne n'a jamais remarqué d'inconvénient à ce sujet.


5 commentaires

Je ne suis pas sûr de comprendre votre dernière remarque sur le standard es6 si vous pouviez élaborer? Imo le fait qu'il soit inoffensif dans jQuery est plus lié au fait qu'il enveloppe une api mutable (le DOM), alors que dans le cas de OP, il serait en fait logique que les vecteurs soient immuables.


La surcharge getter / setter de jQuery n'est pas si grave, mais ils ont fait d'autres surcharges qui étaient terribles, IMO. Comme .toggle () étant à la fois pour les événements et pour changer l'état visible des éléments. Ensuite, il y a le $ , qui est fortement surchargé pour très peu d'avantages par rapport à la fourniture de méthodes judicieusement nommées.


@ziggywiggy "La surcharge getter / setter de jQuery n'est pas si grave" signifie que rien ne va pas, c'est ce que l'OP demande. Sur le reste, bien sûr, nous pouvons discuter.


@LucaFagioli: Cela signifie que ce n'est pas si mal. En d'autres termes, certains peuvent suggérer qu'une telle surcharge entraîne toujours une mauvaise conception d'API. Ce sont des questions d’opinion. Certains langages statiquement typés refusent d'inclure des fonctionnalités de surcharge de méthode pour cette raison, tandis que d'autres sont d'accord avec cela. Mais le but de mon commentaire était de s'assurer que l'OP comprenait que jQuery a des exemples de surcharge raisonnable (getter / setter), et juste une surcharge vraiment désagréable aussi.


Nous pouvons discuter d'une mauvaise conception d'API (et je suis d'accord avec vous: je n'aime pas ça). Mais je ne trouve aucune raison technique de le définir comme une "mauvaise pratique".



0
votes

Je vois trois problèmes avec cette classe.

  1. Imo. le plus gros problème avec ce code n'est pas cette partie x (x = null) {...} mais celle-ci

    if (x) {
        this._x = x
    } else {
        return this._x
    }
    

    Commençons par le plus évident: vector.x (0) définit-il la valeur x sur 0 ? Qu'en est-il de vector.x ("0") ?

    Ensuite, lorsque vous ajoutez une logique à votre fonction pour toujours convertir l'argument en un nombre, qu'en est-il de NaN, "", [], + [], {}, nul et non défini ? Et croyez-moi, plusieurs de ces valeurs finiront là.

    Le problème que je vois ici est que votre fonction commence à avoir du mal à déterminer si elle doit définir ou obtenir la valeur.

  2. Surcharger une fonction signifie une logique supplémentaire qui doit s'exécuter, chaque fois que la fonction est appelée. De manière générale, ce n'est pas un problème, mais ici nous parlons du getter et du setter pour les propriétés d'un vecteur dans un moteur de jeu. Ces fonctions seront appelées des milliers de fois à chaque image. Cela a un impact considérable sur les performances.

  3. Et ceci est lié au n ° 2. Que vous utilisez un vecteur de classe pour cela. Je rendrais cela aussi léger que possible et utiliserais simplement des littéraux pour cela:

    const myVec = {x: 1, y: 2};

Et une astuce sur la route, votre code n'en contient pas beaucoup ; vous devriez commencer à les utiliser. Même si le moteur les insère pour la plupart correctement, il y aura éventuellement des situations où votre code ne veut pas dire ce que vous vouliez dire sans eux.


1 commentaires

En mettant ces problèmes de côté, je me demande si surcharger les méthodes de classe de cette manière est une bonne pratique ou non. Merci pour le conseil n ° 3, je serai sûr de l'utiliser.