简体   繁体   English

未捕获的TypeError:函数不是函数

[英]Uncaught TypeError: Function is not a function

I am getting Fib.inputValidate is not a function 我正在获取Fib.inputValidate is not a function

I am wanting to run the inputValidate method so that on keyup the input validates both as an integer and as a Fibonacci number: 我想运行inputValidate上方法使得keyup输入验证既作为integer和作为Fibonacci数:

HTML looks like this: HTML看起来像这样:

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

Javascript ES6: Javascript ES6:

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

The real problem is that the this inside event handlers is not what you think it is. 真正的问题是,内部事件处理程序中的this不是您认为的那样。 The this inside the event handler will be the (DOM) element that fired the event, not the instance of your class. 事件处理程序中的this将是引发事件的(DOM)元素,而不是类的实例。

Now while you were trying to fix the real problem, you ended up with another problem , which is that you are shadowing the class methods with properties that have as values the empty string '' . 现在,当您尝试解决实际问题时,最终遇到了另一个问题 ,那就是,您正在使用带有空字符串''作为值的属性来遮盖类方法。

To fix this, just remove the constructor all together as it doesn't do anything, and fix the issue with the this inside the event listener. 要解决此问题,只需将构造函数全部删除,因为它不会执行任何操作,并在事件侦听器中解决this的问题。 To do that you have plenty of ways: 为此,您有很多方法:

  1. Use a variable outside the event listener scope called, for example, that , assign this to it and use that instead of this inside the event listener. 使用所谓的事件监听范围,例如外部变量, that ,分配this给它使用that不是this事件监听器里。

Like so: 像这样:

var that = this;
field.addEventListener("keyup", function(e) {
    // use 'that' instead of 'this'
    if(that.isInt(valueParsed) ...
});
  1. Use an arrow function because arrow functions use their surrounding this value: 使用箭头函数,因为箭头函数使用其周围的this值:

Like so: 像这样:

// notice the arrow function passed to addEventListener
field.addEventListener("keyup", e => {
    // you can now use 'this' here with no problems
    if(this.isInt(valueParsed) ...
});
  1. bind your event handler to the instance of your class. bind事件处理程序bind到类的实例。 bind ing a function will create a new function that always have its this value set to whatever you set it to. bind函数将创建一个新函数, this函数始终this值设置为您设置的值。

Like so: 像这样:

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

Working code: Using an arrow function 工作代码:使用箭头功能

 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(); 
 <form id="fibonacci-form" action="" method="post"> <input id="fibonacci" type="text" name="fibonacci" /> </form> 

Enhanced working code: 增强的工作代码:

There still are some issues with your code that are related to the functionality rather than errors: 您的代码中仍有一些与功能有关的问题,而不是与错误有关的问题:

  1. You declare functions as having arguments but you are not using them. 您将函数声明为具有参数,但没有使用它们。 For instance, the valueParsed argument is not used at all by even though it is an argument in all functions, instead you are fetching it from the DOM element every time. 例如,即使valueParsed参数是所有函数中的参数,也根本不会使用它,而是每次都从DOM元素中获取它。 Use the argument. 使用参数。
  2. The valueParsed (now used as argument) will be initialized inside inputValidate . valueParsed (现在用作参数)将在inputValidate内部初始化。 It should be fetched from within the event listener not from outside it (every time the event fires we should get a new value for valueParsed ). 应该从事件侦听器内部而不是外部获取(每次事件触发时,我们都应该为valueParsed获取新值)。
  3. For validation use Number instead of parseInt if you want to exclude float numbers (using parseInt will let float numbers pass validation as it takes only the integer bit from them). 对于验证,如果要排除浮点数,请使用Number而不是parseInt (使用parseInt将使浮点数通过验证,因为它仅从浮点数中获取整数位)。 Also if validation fail, return to stop further code from executing. 同样,如果验证失败,请return以停止执行其他代码。 It (validation) still not very good though, I'll leave that to you. 不过,它(验证)仍然不是很好,我会留给您。
  4. Suggestion: You may want to use a button and listen for clicks on it instead of listening for keydown input on the field which is annoying. 建议:您可能想使用一个按钮并听其点击,而不是听烦人的字段上的keydown输入。 Create a button, and when the user clicks the button then check if the number they entered in the field is a Fibbonacci one or not. 创建一个按钮,然后当用户单击该按钮时,检查他们在字段中输入的数字是否是斐波那契数。 You would only change a line or two of code to achieve that. 您只需更改一行或两行代码即可实现。

 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(); 
 <form id="fibonacci-form" action="" method="post"> <input id="fibonacci" type="text" name="fibonacci" /> </form> 

Remove (or empty) your constructor. 删除(或清空)您的构造函数。 Class methods are inherited by instances of the class automatically, and as it is your constructor is simply overriding them with properties whose values are empty strings. 类方法是由类的实例自动继承的,并且因为它是构造函数,因此只需将其值为空字符串的属性覆盖它们即可。

Remove the this.inputValidate and const inputValidate from your constructor. 从构造const inputValidate删除this.inputValidateconst inputValidate And write your method this way... 然后这样写你的方法...

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

Problem 问题

Your constructor is overwriting every single function in your class. 您的构造函数将覆盖类中的每个函数。 Here's what actually happens to each method (I'm using isInt() as an example, but it's exactly the same for each one): 这是每种方法实际发生的情况(我以isInt()为例,但每个方法都完全相同):

You set isInt to '' (empty string) in the constructor: 您在构造函数中将isInt设置为'' (空字符串):

const isInt = '';

Then, you create a property named isInt , and set it to isInt the string: 然后,创建一个名为isInt的属性,并将其设置为isInt字符串:

this.isInt = isInt;

So isInt ends up being an empty string. 所以isInt最终是一个空字符串。 Here's a minified example: 这是一个缩小的示例:

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

As you can see, the property isInt is equal to "" (empty string), which is why you can't call it like a function - it's a string. 如您所见,属性isInt等于"" (空字符串),这就是为什么您不能像函数一样调用它的原因-它是一个字符串。

Solution

Place the function declarations within the constructor: 将函数声明放在构造函数中:

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

Problem raised for below lines in your code. 在您的代码下面的行中提出了问题。

const inputValidate = ''; const inputValidate ='';

this.inputValidate = inputValidate; this.inputValidate = inputValidate;

what does it mean, it means const variable inputValidate assigned to this.inputValidate , So this.inputValidate is not a function. 这是什么意思,它意味着将const变量inputValidate分配给this.inputValidate ,所以this.inputValidate不是函数。

In contrast function inputValidate(valueParsed, isInt) added into prototype of the created object for the class by nature. 相反, 自然地,将函数inputValidate(valueParsed,isInt)添加到该类的创建对象的原型中。

So, when you called below lines 所以,当您在下面的行中调用时

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

then find Fib.inputValidate in the class/constructor functions first, if not found then find Fib.inputValidate in prototype. 然后在类/构造函数中找到Fib.inputValidate ,如果找不到,则在原型中找到Fib.inputValidate

so, when you called Fib.inputValidate() then it finds the function in its constructor function, but it founds Fib.inputValidate is a property like variable but not function. 因此,当您调用Fib.inputValidate()时,它将在其构造函数中找到该函数,但发现Fib.inputValidate是一个类似于变量的属性,但不是函数。

Thats why showing Uncaught TypeError: Function is not a function 那就是为什么显示Uncaught TypeError:Function不是一个函数

For clear conception you can read the article enter link description here 为了使概念清晰,您可以阅读文章, 在此处输入链接描述

Actually there is no class in javascript but ES6 introduce a class keyword, Actually this class keyword simply syntactic sugar. javascript中实际上没有类,但是ES6引入了class关键字,实际上,该class关键字只是语法糖。

So everyone should keep in mind actual scenario of Class. 因此,每个人都应牢记Class的实际情况。

Finally some modification of your code: 最后,对您的代码进行一些修改:

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

Now Fib.inputValidate() will be reachable. 现在,Fib.inputValidate()将可访问。

And finally into the keypress/keyup or any other event this always point the Dom element so if you use arrow function for keypress/keyup or any other event then this will point the class object. 最后进入keypress / keyup或任何其他事件, 总是指向Dom元素,因此,如果将箭头功能用于keypress / keyup或任何其他事件,则将指向类对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM