【问题标题】:Uncaught TypeError: Function is not a function未捕获的类型错误:函数不是函数
【发布时间】:2019-01-14 23:38:11
【问题描述】:

我收到Fib.inputValidate is not a function

我想运行inputValidate 方法,以便在keyup 上输入验证为integerFibonacci 数字:

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.[function] = [function]
  • 我刚做了这个,但是在keyup 我得到this.isInt is not a function。
  • 你的构造函数正在用一个空字符串覆盖它的所有函数。
  • @RobMyrick 这是一个不同的problem

标签: javascript html ecmascript-6


【解决方案1】:

真正的问题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 函数将创建一个新函数,该函数始终将其 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>

【讨论】:

    【解决方案2】:

    删除(或清空)您的构造函数。类方法由类的实例自动继承,因为它是您的构造函数,所以只需使用值为空字符串的属性覆盖它们。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        问题

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

        【讨论】:

        • 为什么要将所有方法移到构造函数中。 OP 不需要,他只需要解决 inputValidate 函数的问题(this 不是类的实例),这导致他重写构造函数中的方法。你没有解决这个问题,所以基本上你只是让代码变得更糟。
        • @ibrahimmahrir 抱歉,我不确定我是否关注。您是否建议删除所有 const 行或其他内容?
        • 没有。我要说的是,您将方法移到了构造函数中,这不是一个好主意,因为它们应该像 OP 一样在它之外。 OP 的问题是在inputValidate 内部,他设置了一个事件侦听器并在该事件处理程序中使用this。由于事件处理程序中的this 是元素而不是实例,因此代码不起作用。 OP 试图通过将方法分配给构造函数中的变量来解决这个问题,但没有奏效,然后 OP 尝试将变量分配给构造函数中的方法,但这也不起作用。
        • 我怎么知道这个? OP 之前确实发布了另一个问题,但他已将其删除。
        • 啊,我不知道 - 我寻找其他问题,但我有
        【解决方案5】:

        代码中以下行出现问题。

        const inputValidate = '';

        this.inputValidate = inputValidate;

        什么意思,就是把const变量inputValidate赋给 this.inputValidate,所以 this.inputValidate 不是函数。

        相比之下,函数inputValidate(valueParsed, isInt)自然会添加到类的创建对象的原型中。

        所以,当你调用下面的行时

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

        然后首先在类/构造函数中找到Fib.inputValidate,如果没有找到则在prototype中找到Fib.inputValidate

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

        这就是为什么显示 Uncaught TypeError: Function is not a function

        为了清晰的概念你可以阅读文章enter link description here

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

        所以大家要牢记Class的实际场景。

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

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

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

        最后进入 keypress/keyup 或任何其他事件 this 始终指向 Dom 元素,因此如果您使用 arrow function 进行 keypress/keyup 或任何其他事件,那么 this 将指向类对象。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-12-19
          • 2014-07-14
          • 2022-11-19
          • 2019-06-06
          • 2019-05-24
          • 2021-12-15
          • 2019-10-26
          相关资源
          最近更新 更多