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

时间:2019-01-14 23:38:12

标签: javascript html ecmascript-6

我得到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());

5 个答案:

答案 0 :(得分:2)

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

现在,当您尝试解决实际问题时,最终遇到了另一个问题,这是因为您用属性值为空字符串{{1} }。

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

  1. 在事件侦听器范围之外使用一个变量,例如,this,为其分配that,并在事件侦听器内部使用this代替that。 / li>

像这样:

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

像这样:

this
  1. // notice the arrow function passed to addEventListener field.addEventListener("keyup", e => { // you can now use 'this' here with no problems if(this.isInt(valueParsed) ... }); 将事件处理程序添加到类的实例。 bind调用一个函数将创建一个新函数,该函数始终将其bind的值设置为您设置的值。

像这样:

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

增强的工作代码:

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

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

从构造函数中删除this.inputValidateconst inputValidate。然后用这种方式编写您的方法...

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

答案 3 :(得分:0)

问题

您的构造函数将覆盖类中的每个函数。这是每种方法实际发生的情况(我以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);

答案 4 :(得分:0)

在您的代码下面的行中引发的问题。

  

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 是一个类似于变量的属性,但不是功能。

这就是为什么显示未捕获的TypeError:函数不是函数

有关概念,您可以阅读enter link description here

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

所以每个人都应该记住课堂的实际情况。

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

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

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

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