在初学JS时犯的一些错误

4.1k words

表示最近在学JS, 相对个人以前学的Python, JAVA之类的语言, JS的语言确实有一些”奇葩”. 把初学时的一些语法错误记录下来,方便自己以后查阅, 如果能帮助到读这篇文章的你自然就更好了.

number 与 string 相加/减/乘/除

Example 1:

1
2
var a  = "5" + 2;   // the result is "52"
var b = 2 + "5"; // the result is "25"

在 number 与 string 相加时, number 会被转化为 string, 然后这两个字符串会根据前后顺序做拼接. 这一点上, 有点类似与 JAVA 中的System.out.println(2 + "5");, 数字遇到加号时会变为字符串,让后做拼接运算.

Example 2:

1
2
var a  = "5" + 2 + 2;   // the result is "522"
var b = 2 + 2 + "5"; // the result is "45"

如果在 string 前有 number 的运算, 那么 number 仍然会进行正常的 number 之前的运算,直到遇到 string, number 才会 被转为 string.
反过来, 如果在 number 前线遇到了 string, 那么后续的每一个 number 都会被当作 string 进行运算.
如果对 JAVA 熟悉一点, 这一点也还好理解, 这跟JAVA中System.out.println(2 + 2 + "5");System.out.println("5" + 2 + 2);的结果也是一样的.

Example 3:

1
2
3
var x = "5" - 2;  // the result is 3
var y = "5" * 2; // the result is 10
var z = "5" / 2; // the result is 2.5

比起加法, 减/乘/除 相对更简单一点,只要 string 能转化为 number, 那么 string 就会转化为 numner 进行运算.

Undefined 不是 Null

在 JS 中, null 更多是针对 objects 而言的, 而 undefined 则更多是针对 variables, properties, methods 而言的.
要变成null, 一个 object 首先要被定义, 否则只能变成 undefined.

因此 如果要判断一个 object 是否存在(不为空 且 已被定义),那么以下发发是的:

1
if (myObj !== null && typeof myObj !== "undefined")

这样的结果则是 Uncaught ReferenceError: myObj is not defined(…)
所以 要判断是否为 null 前必须要判断是否 已被定义, 所以调换以下判断顺序就可以解决上面的问题了:

1
if (typeof myObj !== "undefined" && myObj !== null)

只有 myObj 被定义了 且 不为 null 时, 上述判断语句才能被盘为 true, 否则均为 false.

向Array添加元素的方式

如果已知一个数组arr = [1, 2, 3], 那么向它的末尾添加元素的方式至少有以下三种:

Example:

1
2
3
arr[3] = 4; // 方法1
arr[arr.length] = 4; // 方法2
arr.push(4); // 方法3

虽然这三种都可以完成预期目标,但极不推荐方法1,原因是用数字索引很容易产生不期望的错误,仍旧以arr = [1, 2, 3]为例。假设 我不小心写成了arr[4] = 4会怎样呢?实际结果是arr会变成:

1
[1, 2, 3, undefined, 4]

可以看出,JS在此时会自动填充undefined。所以为了避免这种情况的发生,强烈建议采用方法2和方法3向数组末尾添加元素.

断开的 return 语句

Example:

1
2
3
4
function myFun() {
return
10;
}

猜猜调用 myFun() 时, 它会返回什么 ? 经测试正解是 undefined .
原因是 JS 是这样解释的:

1
2
3
4
function myFun() {
return ; // Attention
10;
}

JS 会在那一行的末尾自动补上一个分号以示结束. 所以结果自然是 undefined.

Switch 的严格比较

先看例子:

1
2
3
4
5
6
7
8
9
var x = 10;
switch (x) {
case "10":
window.alert("run in case");
break;
default:
window.alert("run in default");
break;
}

在这个例子中, 网页跳出的弹窗中会显示那条信息呢?经测试, 是后一条(“run in default”),而不是前一条(“run in case”).
原因很简单, 10 === "10" 是 false. 所以 不能进入第一个case, 最终会进入到 default 中.

精度的损失

不管是什么语言, 浮点数的精度损失不可避免,有的损失比较小, 可以不用太在意,而有的损失可能就比较大,需要额外的注意.
Example:

1
2
3
4
5
6
7
var x = 0.1;
var y = 0.2
var z = x + y;
console.log(z);
if (z == 0.3) {
window.alert("Run");
}

我经过实际运行可以发现 z 的 值其实是 0.30000000000000004 . 跟期望的有点出入. 所以在实际运行网页上不会有弹窗出现.
就算是写成 var z = 0.1 + 0.2;也只是换汤不换药.
除非直接写成 var z = 0.3
如果需要要到x, y变量是可以考虑这么写:

1
var z = (x * 10 + y * 10) / 10;       // z will be 0.3

object 之间不能比较

Example:

1
2
3
4
5
6
var x = new String("John");
var y = new String("John");

// (x == y) false, different objects
// (x == x) true, same objects
// (x === y) true

从中也可以看出,对于 string, 极不建议用构造对象的方式声明.

script 放在head 中还是 body 中

理论上讲,把JS放在哪都可以运行,但最近我个人在学习过程中就遇到了一个因放置位置而引起的问题。
就我个人编写的下面这个例子来说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<!-- 1 <script>
var demo = document.getElementById("demo");
window.alert(demo);
</script> -->
<title></title>
</head>
<body>
<p id="demo"></p>
<!-- 2 <script>
var demo = document.getElementById("demo");
window.alert(demo);
</script> -->
</body>
</html>

如果是写在1处,那么结果是窗口弹出 null,但如果是2处,则正确取到了对象。google之后的结果是:放在 head 和 body 处各有千秋,不能一概而论。但至少如果是放在body里的话,能使 html 的加载在 js 前,相对而言,能使 html 免于因 js 加载受阻而造成影响。所以,在这里只能是先提个醒了,如果放在 head 中运行异常的话,可以试试放在 body 处。

a标签的文本如何不做跳转

少数时候不希望被 a 标签包围的文本被点击后做跳转, 只希望停留在当前页面, 也不是重新载入至当前页面.
此时需要在 a 标签的 href 属性里如下写:

1
<a href="javascript:;">Text</a>

删除元素应由其父级进行操作

在进行DOM操作时,如果要删除某一元素,如:

1
2
3
4
5
6
7
8
9
10
<html>
<head></head>
<body>
<ul>
<li id="target">1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
</html>

要删除 id 为 target 的 li 标签,那么应由其父级对他删除, 而获取其父级则可以通过调用其 parentNode 属性:

1
2
var target = document.getElementById('target');
target.parentNode.removeChild(target);

而以下是我初学是犯的低级错误:

1
2
var target = document.getElementById('target');
document.body.removeChild(target);

参考资料 : w3schoold