10 个 JavaScript 容易犯的错误
JavaScript 是一门简单的解释性编程语言,学习他很容易,但是语言语法去不严谨,这就导致了很容易犯错,但是却不知道错误在哪里,今天给大家列举一下 10 个 JavaScript 容易犯的错误,也许你也这么干过?
1、失踪的大括号
JavaScript 经常犯的错误是省略括号后面的声明,比如:if
、else
、 while
和 for
。虽然这是允许的,你必须格外小心,因为这种做法往往是隐藏的问题和错误的来源。看下面的例子:
// Say hello to Gandalf hello('Gandalf'); function hello(name){ // This code doesn't do what the indentation implies! if(name === undefined) console.log('Please enter a username!'); fail(); // The following line is never reached: success(name); } function success(name){ console.log('Hello, ' + name + '!'); } function fail(){ throw new Error("Name is missing. Can't say hello!"); }
虽然 fail()
函数是缩进的,看起来好像是属于 if 语句。所以大括号总是围绕其中的代码块是一个很好的做法,即使是只有一个语句。
2、缺少分号
当 JavaScript 解析,有一个过程称为自动分号的插入。顾名思义,解析器是乐意把你丢失分号。此功能的目的是使 JavaScript 更平易近人,更容易写的初学者。然而你应该总是包含分号,因为有在忽略他们的危险。这里有一个例子:
console.log('Welcome the fellowship!') ['Frodo', 'Gandalf', 'Legolas', 'Gimli'].forEach(function(name){ hello(name) }) function hello(name){ console.log('Hello, ' + name + '!') }
因为有一个分号在 3 行失踪,解析器假设开始第五行是一个尝试使用数组语法访问属性访问器,而不是一个独立的数组,这不是我们所期望的,在一个类型错误的结果。解决方法是简单的–总是写分号。 一些有经验的 JavaScript 开发者喜欢把分号但是,他们非常清楚的错误,这可能会导致和知道如何阻止他们。
3、变量类型强制转换
JavaScript 是动态类型。这意味着,你不需要指定类型时,宣布一个新的变量,并可以自由转让或将其价值。这使得写的不是像 C 或 Java 非常容易,但是你打开门,潜在的错误,在其他语言被编译步骤期间。这里有一个例子:
var textBox = document.querySelector('input'); textBox.addEventListener('input', function(){ // textBox.value holds a string. Adding 10 appends // the string '10', it doesn't perform an addition.. console.log(textBox.value + ' + 10 = ' + (textBox.value + 10)); });
这个问题可以通过使用固定的容易 parseInt(textBox.value, 10)
将字符串转换为数字前加 10。 取决于你如何使用变量,运行时可能会决定它应该在一种或另一种类型转换。这是众所周知的类型强制。为了防止类型的隐式转换比较时,变量如果报表,您可以使用严格的平等的检查(===)。
4、忘了 var
另一种做法,初学者是有罪的,被遗忘的使用 var
关键词时,变量的声明。JavaScript 是非常宽容的,并在第一时间看到你使用一个可变的无 var
语句,它将为你默默地宣布全球。这可以是微妙的错误源。这里有一个例子,这也显示出不同的错误–缺少逗号时声明多个变量一次:
var a = 1, b = 2, c = 3; function alphabet(str){ var a = 'A', b = 'B' // Oops, missing ',' here! c = 'C', d = 'D'; return str + ' ' + a + b + c + '…'; } console.log( alphabet("Let's say the alphabet!") ); // Oh no! Something went wrong! c has a new value! console.log(a, b, c);
当解析器达到 4 线,它会自动插入一个分号,然后解释 C 和 D 5 号线的声明为全局。这将导致外部 C 变量的值的变化。
5、浮动小数的运算
几乎所有的编程语言都有这个错误,包括 JavaScript 。由于道路浮点数在内存中表示算术运算,并没有你想的那么精确。这里有一个例子:
var a = 0.1, b = 0.2; // Surprise! this is false: console.log(a + b == 0.3); // Because 0.1 + 0.2 does not produce the number that you expect: console.log('0.1 + 0.2 = ', a + b);阅读更多JavaScript的陷阱在这里。
为了解决这个问题,你不应该使用小数,如果你需要绝对正确使用整数。
6、在文字使用构造函数
当 Java 和 C 程序员开始编写 JavaScript,他们通常更喜欢使用构造函数创建对象:new Array()
、 new Object()
、new String()
。虽然他们都非常支持,建议使用文字符号:[]{}""
,因为构造函数有微妙的特点:
/* Using array constructors is valid, but not recommended. Here is why. */ // Create an array with four elements: var elem4 = new Array(1,2,3,4); console.log('Four element array: ' + elem4.length); // Create an array with one element. It doesn't do what you think it does: var elem1 = new Array(23); console.log('One element array? ' + elem1.length); /* String objects also have their warts */ var str1 = new String('JavaScript'), str2 = "JavaScript"; // Strict equality breaks: console.log("Is str1 the same as str2?", str1 === str2);
解决的方法很简单:尝试总是使用文字符号。
7、不知道变量的作用范围
初学者的一个难以理解的概念是 JavaScript 的作用域规则和关闭。这是理所当然的:
// Print the numbers from 1 to 10, 100ms apart. Or not. for(var i = 0; i < 10; i++){ setTimeout(function(){ console.log(i+1); }, 100*i); } /* To fix the bug, wrap the code in a self-executing function expression: for(var i = 0; i < 10; i++){ (function(i){ setTimeout(function(){ console.log(i+1); }, 100*i); })(i); } */
功能保留的能见度变量在其父母的范围。但是,因为我们有一个延缓执行 setTimeout
的时候,功能,实际运行,循环已经完成 I
变量递增到 11。 自我评论工作执行的功能,因为它复制 I
变量的值和保持一个私人复制每个超时功能。
8、使用 eval
它被认为是一种不好的做法,当你使用它的时候,有一个更好、更快的方法。
/* Using eval to access properties dynamically */ var obj = { name: 'Foo Barski', age: 30, profession: 'Programmer' }; // Which property to access? var access = 'profession'; // This is a bad practice. Please don't do it: console.log( eval('obj.name + " is a " + obj.' + access) ); // Instead, use array notation to access properties dynamically: console.log( obj.name + " is a " + obj[access]); /* Using eval in setTimout */ // Also bad practice. It is slow and difficult to read and debug: setTimeout(' if(obj.age == 30) console.log("This is eval-ed code, " + obj[access] + "!");', 100); // This is better: setTimeout(function(){ if(obj.age == 30){ console.log('This code is not eval-ed, ' + obj[access] + '!'); } }, 100);
eval
是一个字符串。调试从 eval 块所产生的信息是难以理解的,你要逃避的单和双引号。更不用说它比 JavaScript 慢。不要使用 eval,除非你知道你正在做什么。
9、不了解异步代码
有一些独特的 JavaScript,几乎一切都是异步的,你需要通过回调函数来通知事件。这不直观的初学者,他们很快就发现自己抓头上的错误,是很难理解的。这里有一个例子中,我使用 freegeoip 获取你的位置的 IP 服务:
var userData = {}; // Fetch the location data for the current user. load(); // Output the location of the user. Oops, it doesn't work! Why? console.log('Hello! Your IP address is ' + userData.ip + ' and your country is ' + userData.country_name); // The load function will detect the current visitor's ip and location with ajax, using the // freegeoip service. It will place the returned data in the userData variable when it's ready. function load(){ $.getJSON('http://freegeoip.net/json/?callback=?', function(response){ userData = response; // Uncomment this line to see what is returned: // console.log(response); }); }
即使 console.log
之后 load()
函数调用,它实际上是在执行读取数据。
10、滥用事件侦听器
让我们说,你想要听一个按钮点击,但只有一个复选框。这里是如何一个初学者可能做它(jQuery):
var checkbox = $('input[type=checkbox]'), button = $('button'); // We want to listen for clicks only when the checkbox is marked. checkbox.on('change', function(){ // Is the checkbox checked? if(this.checked){ // Listen for clicks on the button. button.on('click', function(){ // This alert is called more than once. Why? alert('Hello!'); }); } });
这显然是错误的。理想情况下,你应该倾听事件只有一次,就像我们是复选框的变化事件。在按钮上绑定多个 button.on('click')
事件侦听器,是永远不会被删除,结果我将把它作为为读者做这工作的一个练习。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论