[英]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: 为此,您有很多方法:
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) ...
});
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) ...
});
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: 您的代码中仍有一些与功能有关的问题,而不是与错误有关的问题:
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. 使用参数。 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
获取新值)。 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. 不过,它(验证)仍然不是很好,我会留给您。 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.inputValidate
和const inputValidate
。 And write your method this way... 然后这样写你的方法...
inputValidate = (valueParsed, isInt) => {
// do stuff here
};
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
等于""
(空字符串),这就是为什么您不能像函数一样调用它的原因-它是一个字符串。
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.