繁体   English   中英

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

[英]Uncaught TypeError: Function is not a function

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

我想运行inputValidate上方法使得keyup输入验证既作为integer和作为Fibonacci数:

HTML看起来像这样:

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

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

真正的问题是,内部事件处理程序中的this不是您认为的那样。 事件处理程序中的this将是引发事件的(DOM)元素,而不是类的实例。

现在,当您尝试解决实际问题时,最终遇到了另一个问题 ,那就是,您正在使用带有空字符串''作为值的属性来遮盖类方法。

要解决此问题,只需将构造函数全部删除,因为它不会执行任何操作,并在事件侦听器中解决this的问题。 为此,您有很多方法:

  1. 使用所谓的事件监听范围,例如外部变量, that ,分配this给它使用that不是this事件监听器里。

像这样:

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

像这样:

// 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事件处理程序bind到类的实例。 bind函数将创建一个新函数, this函数始终this值设置为您设置的值。

像这样:

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

工作代码:使用箭头功能

 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> 

增强的工作代码:

您的代码中仍有一些与功能有关的问题,而不是与错误有关的问题:

  1. 您将函数声明为具有参数,但没有使用它们。 例如,即使valueParsed参数是所有函数中的参数,也根本不会使用它,而是每次都从DOM元素中获取它。 使用参数。
  2. valueParsed (现在用作参数)将在inputValidate内部初始化。 应该从事件侦听器内部而不是外部获取(每次事件触发时,我们都应该为valueParsed获取新值)。
  3. 对于验证,如果要排除浮点数,请使用Number而不是parseInt (使用parseInt将使浮点数通过验证,因为它仅从浮点数中获取整数位)。 同样,如果验证失败,请return以停止执行其他代码。 不过,它(验证)仍然不是很好,我会留给您。
  4. 建议:您可能想使用一个按钮并听其点击,而不是听烦人的字段上的keydown输入。 创建一个按钮,然后当用户单击该按钮时,检查他们在字段中输入的数字是否是斐波那契数。 您只需更改一行或两行代码即可实现。

 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> 

删除(或清空)您的构造函数。 类方法是由类的实例自动继承的,并且因为它是构造函数,因此只需将其值为空字符串的属性覆盖它们即可。

从构造const inputValidate删除this.inputValidateconst inputValidate 然后这样写你的方法...

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

问题

您的构造函数将覆盖类中的每个函数。 这是每种方法实际发生的情况(我以isInt()为例,但每个方法都完全相同):

您在构造函数中将isInt设置为'' (空字符串):

const isInt = '';

然后,创建一个名为isInt的属性,并将其设置为isInt字符串:

this.isInt = isInt;

所以isInt最终是一个空字符串。 这是一个缩小的示例:

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

如您所见,属性isInt等于"" (空字符串),这就是为什么您不能像函数一样调用它的原因-它是一个字符串。

将函数声明放在构造函数中:

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

在您的代码下面的行中提出了问题。

const inputValidate ='';

this.inputValidate = inputValidate;

这是什么意思,它意味着将const变量inputValidate分配给this.inputValidate ,所以this.inputValidate不是函数。

相反, 自然地,将函数inputValidate(valueParsed,isInt)添加到该类的创建对象的原型中。

所以,当您在下面的行中调用时

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

然后在类/构造函数中找到Fib.inputValidate ,如果找不到,则在原型中找到Fib.inputValidate

因此,当您调用Fib.inputValidate()时,它将在其构造函数中找到该函数,但发现Fib.inputValidate是一个类似于变量的属性,但不是函数。

那就是为什么显示Uncaught TypeError:Function不是一个函数

为了使概念清晰,您可以阅读文章, 在此处输入链接描述

javascript中实际上没有类,但是ES6引入了class关键字,实际上,该class关键字只是语法糖。

因此,每个人都应牢记Class的实际情况。

最后,对您的代码进行一些修改:

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

现在,Fib.inputValidate()将可访问。

最后进入keypress / keyup或任何其他事件, 总是指向Dom元素,因此,如果将箭头功能用于keypress / keyup或任何其他事件,则将指向类对象。

暂无
暂无

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

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