1
votes

Uncaught TypeError: la fonction n'est pas une fonction

J'obtiens Fib.inputValidate is not a function

Je souhaite exécuter la méthode inputValidate afin que sur keyup le l'entrée valide à la fois comme un entier et comme un Fibonacci nombre:

HTML ressemble à ceci:

class Fibonacci {

  constructor() {
    const isPerfectSquare = '';
    const isFibonacci = '';
    const isInt = '';
    const inputValidate = '';
    this.isPerfectSquare = isPerfectSquare;
    this.isFibonacci = isFibonacci;
    this.isInt = isInt;
    this.inputValidate = inputValidate;
  } // constructor

  inputValidate(valueParsed, isInt) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    field.addEventListener("keyup", function(e) {
      if (this.isInt(valueParsed) === false && field.value !== '') { 
        alert('Please enter a valid integer.'); 
      } 

      if(this.isFibonacci(valueParsed)) {
        alert(valueParsed + ' is a Fibonacci Number.');  
      } else {
        alert(valueParsed + ' is not a Fibonacci Number.'); 
      }
    });
  }

  isInt(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    return !isNaN(valueParsed) && valueParsed == valueParsed.toFixed();
  }

  isPerfectSquare(valueParsed) { 
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
    if (field.value !== '') { 
      return (squaredValue * squaredValue == valueParsed); 
    }
  } 

  isFibonacci(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0)); 
      return this.isPerfectSquare(5 * valueParsed * valueParsed + 4) || this.isPerfectSquare(5 * valueParsed * valueParsed - 4); 
  } 
} // class

let Fib = new Fibonacci();
console.log(Fib.inputValidate());

Javascript ES6:

<form id="fibonacci-form" action="" method="post">
  <input id="fibonacci" type="text" name="fibonacci"/>
</form>


4 commentaires

Supprimez simplement tout this. [Function] = [function] du constructeur.


Je viens de faire ça, mais ensuite sur keyup j'obtiens this.isInt n'est pas une fonction.


Votre constructeur remplace toutes ses fonctions par une chaîne vide.


@RobMyrick, c'est un problème < / b>


5 Réponses :


0
votes

Supprimez (ou videz) votre constructeur. Les méthodes de classe sont héritées automatiquement par les instances de la classe, et comme c'est le cas, votre constructeur les remplace simplement par des propriétés dont les valeurs sont des chaînes vides.


0 commentaires

0
votes

Supprimez this.inputValidate et const inputValidate de votre constructeur. Et écrivez votre méthode de cette façon ...

inputValidate = (valueParsed, isInt) => {
 // do stuff here
};


0 commentaires

0
votes

Problème

Votre constructeur écrase chaque fonction de votre classe. Voici ce qui arrive réellement à chaque méthode (j'utilise isInt () comme exemple, mais c'est exactement la même chose pour chacune d'elles):

Vous définissez isInt à '' (chaîne vide) dans le constructeur:

class Fibonacci {

  constructor() {
    this.inputValidate = function(valueParsed, isInt) {
      var field = document.getElementById('fibonacci');
      var valueParsed = parseInt(field.value);
      field.addEventListener("keyup", function(e) {
        if (this.isInt(valueParsed) === false && field.value !== '') {
          alert('Please enter a valid integer.');
        }

        if (this.isFibonacci(valueParsed)) {
          alert(valueParsed + ' is a Fibonacci Number.');
        } else {
          alert(valueParsed + ' is not a Fibonacci Number.');
        }
      });
    }

    this.isInt = function(valueParsed) {
      var field = document.getElementById('fibonacci');
      var valueParsed = parseInt(field.value);
      return !isNaN(valueParsed) && valueParsed == valueParsed.toFixed();
    }

    this.isPerfectSquare = function(valueParsed) {
      var field = document.getElementById('fibonacci');
      var valueParsed = parseInt(field.value);
      var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
      if (field.value !== '') {
        return (squaredValue * squaredValue == valueParsed);
      }
    }

    this.isFibonacci = function(valueParsed) {
      var field = document.getElementById('fibonacci');
      var valueParsed = parseInt(field.value);
      var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
      return this.isPerfectSquare(5 * valueParsed * valueParsed + 4) || this.isPerfectSquare(5 * valueParsed * valueParsed - 4);
    }
  }
} // class

let Fib = new Fibonacci();
console.log(Fib);

Ensuite, vous créez une propriété nommée isInt code >, et définissez-le sur isInt la chaîne:

class Fibonacci {

  constructor() {
    const isInt = '';
    this.isInt = isInt;
  } // constructor

  isInt(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    return !isNaN(valueParsed) && valueParsed == valueParsed.toFixed();
  }
} // class

let Fib = new Fibonacci();
console.log(Fib);

Donc isInt finit par être une chaîne vide. Voici un exemple réduit:

this.isInt = isInt;

Comme vous pouvez le voir, la propriété isInt est égale à "" (chaîne vide), c'est pourquoi vous ne pouvez pas l'appeler comme un function - c'est une chaîne.

Solution

Placez les déclarations de fonction dans le constructeur:

const isInt = '';

5 commentaires

Pourquoi déplaceriez-vous toutes les méthodes dans le constructeur. OP n'a pas besoin de cela, il a juste besoin de résoudre le problème avec la fonction inputValidate ( this n'étant pas l'instance de la classe), ce qui l'amène à remplacer les méthodes dans le constructeur. Vous n'avez pas résolu cela, donc vous venez d'aggraver le code.


@ibrahimmahrir Désolé, je ne suis pas sûr de suivre. Proposez-vous de supprimer toutes les lignes const , ou autre chose?


Non. Ce que je dis, c'est que vous avez déplacé les méthodes dans le constructeur, ce qui n'est pas une bonne idée car elles devraient être en dehors de celui-ci comme OP l'a déjà fait. Le problème d'OP est qu'à l'intérieur de inputValidate , il définit un écouteur d'événements et utilise this dans ce gestionnaire d'événements. Puisque this à l'intérieur du gestionnaire d'événements est l'élément et non l'instance, le code ne fonctionne pas. OP a essayé de corriger cela en affectant les méthodes en variables dans le constructeur, cela n'a pas fonctionné, OP a ensuite essayé d'assigner des variables aux méthodes à l'intérieur du constructeur, cela n'a pas fonctionné non plus.


Comment le sais-je? OP a posté une autre question plus tôt qu'il a supprimée.


Ah, je ne le savais pas - j'ai cherché d'autres questions, mais j'ai <10k, donc je n'ai pas pu voir celle-là.



0
votes

Problème soulevé pour les lignes ci-dessous dans votre code.

const inputValidate = '';

this.inputValidate = inputValidate;

qu'est-ce que cela signifie, cela signifie la variable const inputValidate affectée à this.inputValidate , donc this.inputValidate n'est pas une fonction.

En revanche, la fonction inputValidate (valueParsed, isInt) ajouté dans le prototype de l'objet créé pour la classe par nature.

Ainsi, lorsque vous avez appelé les lignes ci-dessous

constructor() {
    const isPerfectSquare = '';
    const isFibonacci = '';
    const isInt = '';
    const inputValidate = '';
  } // constructor

, recherchez Fib.inputValidate dans les fonctions de classe / constructeur d'abord, si ce n'est pas trouvé, puis recherchez Fib.inputValidate dans le prototype.

donc, quand vous avez appelé Fib.inputValidate () puis il trouve la fonction dans sa fonction constructeur, mais il trouve que Fib.inputValidate est une propriété comme une variable mais pas une fonction.

C'est pourquoi montrer Uncaught TypeError: Function is not a function

Pour une conception claire, vous pouvez lire l'article entrez la description du lien ici

En fait, là Il n'y a pas de classe en javascript mais ES6 introduit un mot-clé de classe, En fait, ce mot-clé de classe est simplement du sucre syntaxique.

Donc, tout le monde devrait garder à l'esprit le scénario réel de la classe.

Enfin quelques modifications de votre code:

let Fib = new Fibonacci(); 
console.log(Fib.inputValidate());

Maintenant Fib.inputValidate () sera accessible.

Et enfin dans le keypress / keyup ou tout autre événement this pointez toujours l'élément Dom donc si vous utilisez la fonction de flèche pour keypress / keyup ou tout autre événement alors this strong> pointera l'objet de classe.


0 commentaires

2
votes

Le vrai problème est que les gestionnaires d'événements internes this ne sont pas ce que vous pensez. Le this à l'intérieur du gestionnaire d'événements sera l'élément (DOM) qui a déclenché l'événement, pas l'instance de votre classe.

Maintenant, pendant que vous essayiez de résoudre le problème réel, vous vous êtes retrouvé avec un autre problème , qui est que vous observez les méthodes de classe avec des propriétés qui ont comme valeurs la chaîne vide ''.

Pour résoudre ce problème, il suffit de supprimez le constructeur tous ensemble car il ne fait rien, et corrigez le problème avec le this dans l'écouteur d'événements. Pour ce faire, vous avez de nombreuses façons:

  1. Utilisez une variable en dehors de la portée de l'écouteur d'événements appelée, par exemple, that , attribuez-lui this et utilisez that au lieu de ceci dans l'écouteur d'événements.

Comme ceci:

<form id="fibonacci-form" action="" method="post">
  <input id="fibonacci" type="text" name="fibonacci" />
</form>
  1. Utilisez une fonction fléchée car les fonctions fléchées utilisent leur cette valeur environnante:

Comme ça:

class Fibonacci {
  inputValidate() {
    var field = document.getElementById('fibonacci');

    field.addEventListener("keyup", e => {
      var valueParsed = Number(field.value);
      if (this.isInt(valueParsed) === false) {
        alert('Please enter a valid integer.');
        return;
      }

      if (this.isFibonacci(valueParsed)) {
        alert(valueParsed + ' is a Fibonacci Number.');
      } else {
        alert(valueParsed + ' is not a Fibonacci Number.');
      }
    });
  }

  isInt(valueParsed) {
    return !isNaN(valueParsed) && valueParsed == valueParsed.toFixed();
  }

  isPerfectSquare(valueParsed) {
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));

    return (squaredValue * squaredValue == valueParsed);
  }

  isFibonacci(valueParsed) {
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
    return this.isPerfectSquare(5 * valueParsed * valueParsed + 4) || this.isPerfectSquare(5 * valueParsed * valueParsed - 4);
  }
} // class

let Fib = new Fibonacci();
  1. liez votre gestionnaire d'événements à l'instance de votre classe. lier une fonction créera une nouvelle fonction dont la valeur this sera toujours définie sur ce que vous avez défini.

Comme ceci:

<form id="fibonacci-form" action="" method="post">
  <input id="fibonacci" type="text" name="fibonacci" />
</form>

Code de travail: Utilisation d'une fonction fléchée

class Fibonacci {
  inputValidate(valueParsed, isInt) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    field.addEventListener("keyup", e => {
      if (this.isInt(valueParsed) === false && field.value !== '') {
        alert('Please enter a valid integer.');
      }

      if (this.isFibonacci(valueParsed)) {
        alert(valueParsed + ' is a Fibonacci Number.');
      } else {
        alert(valueParsed + ' is not a Fibonacci Number.');
      }
    });
  }

  isInt(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    return !isNaN(valueParsed) && valueParsed == valueParsed.toFixed();
  }

  isPerfectSquare(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
    if (field.value !== '') {
      return (squaredValue * squaredValue == valueParsed);
    }
  }

  isFibonacci(valueParsed) {
    var field = document.getElementById('fibonacci');
    var valueParsed = parseInt(field.value);
    var squaredValue = parseInt(Math.sqrt(valueParsed).toFixed(0));
    return this.isPerfectSquare(5 * valueParsed * valueParsed + 4) || this.isPerfectSquare(5 * valueParsed * valueParsed - 4);
  }
} // class

let Fib = new Fibonacci();
field.addEventListener("keyup", function(e) {
    // you can now use 'this' here with no problems
    if(this.isInt(valueParsed) ...
}.bind(this)); // bind the function to its surronding 'this' value so 'this' inside it will be the same as 'this' outside it

Code de travail amélioré:

Il y a encore des problèmes avec votre code qui sont liés à la fonctionnalité plutôt qu'à des erreurs:

  1. Vous déclarez des fonctions comme ayant des arguments mais vous ne les utilisez pas. Par exemple, l'argument valueParsed n'est pas du tout utilisé par même s'il s'agit d'un argument dans toutes les fonctions, mais vous le récupérez à chaque fois depuis l'élément DOM. Utilisez l'argument.
  2. Le valueParsed (maintenant utilisé comme argument) sera initialisé dans inputValidate . Il doit être extrait de l'écouteur d'événements et non de l'extérieur (chaque fois que l'événement se déclenche, nous devrions obtenir une nouvelle valeur pour valueParsed ).
  3. Pour la validation, utilisez Number au lieu de parseInt si vous souhaitez exclure les nombres flottants (en utilisant parseInt , les nombres flottants passeront la validation au fur et à mesure seulement le bit entier d'eux). De plus, si la validation échoue, retournez pour arrêter l'exécution du code supplémentaire. Cela (la validation) n'est toujours pas très bon, je vous laisse cela.
  4. Suggestion: Vous pouvez utiliser un bouton et écouter les clics dessus au lieu d'écouter l'entrée keydown sur le champ, ce qui est ennuyeux. Créez un bouton, et lorsque l'utilisateur clique sur le bouton, vérifiez si le numéro qu'il a entré dans le champ est un Fibbonacci ou non. Vous ne changeriez qu'une ou deux lignes de code pour y parvenir.

// notice the arrow function passed to addEventListener
field.addEventListener("keyup", e => {
    // you can now use 'this' here with no problems
    if(this.isInt(valueParsed) ...
});
var that = this;
field.addEventListener("keyup", function(e) {
    // use 'that' instead of 'this'
    if(that.isInt(valueParsed) ...
});


0 commentaires