JavaScript躲坑指南(二)

本系列将会写一些在正常工作中会遇到的一些坑,然后分析它们的产生原因及解决办法.本文的内容主要来自<you don’t know JS>及日常工作的问题的一些总结.

关于arguments的使用:

arguments在ES6之前简直就是福音,因为在ES6之前是没有办法取到函数的参数组成的数组的.

但是arguments在使用的过程中还是有一些坑的,我们来看一下:

1
2
3
4
5
6
function foo(a) {
a = 42;
console.log(arguments[0])
}
foo(2); //42
foo(); //undefined

在向函数传递参数的时候,arguments数组中的对应单元会和命名参数建立关联,以得到相同的值,但是当函数在调用的时候没有传递参数时,因为没有参数,自然arguments就无法和函数建立关联了,自然就是undefined.

try/catch/finally的内容执行先后的问题

finally中的代码总是会在try之后执行,如果有catch的话会在catch之后执行.其实也可以把finally中的代码当做一个回调函数.无论出现什么情况,最后一定会被调用.

1
2
3
4
5
6
7
8
9
10
function foo() {
try {
return 42;
} finally {
console.log('hello')
}
console.log('never runs');
}
console.log(foo());
//输出结果: 先输出 hello 再输出返回的值hello

在这里return42先执行,并将foo()函数的返回值设置为42.try执行完毕后执行finally.console.log()显示的是函数的返回值.

对于这个问题还有一个很好玩的东西,就是当你在finally中进行抛出异常时,其实try中的返回值就不生效了.

1
2
3
4
5
6
7
8
9
function foo() {
try {
return 42;
} finally {
throw "oops!"
}
console.log('never runs');
}
console.log(foo()); // Uncaught oops!

其实综上而言,不论try中执行的是什么东西,即使是return或者throw等让函数立即结束的语句,最后finally也会成功执行.但是当finally中抛出异常时,try中的代码其实就相当于无效了.也就是finally中的值会最终覆盖掉try中的值.

关于全局的DOM变量

当我们在文档流中加入 <div id="foo"></div> 时,我们在其下面的js文档中能否找到foo这个变量呢?答案是可以!

1
2
//我们直接在文档的下面进行类型判定
console.log(typeof foo); //输出结果是object, WTF?

关于属性的屏蔽

当我们在原型链中为底层函数操作原型链中的属性进行算术运算时,属性被被底层函数给屏蔽掉.

1
2
3
4
5
6
7
var anotherObject = {
a: 2
}
var myObject = Object.create(anotherObject);
console.log(myObject.a);
myObject.a++;
console.log(myObject.a,anotherObject.a);

其实想到原理就很简单,因为当我们把myObject中的a,也就是anotherObject中的a调用之后,相应的myObject.a会得到anotherObject中的a的值,也就是2.但是当我们对myObject执行其属性的自加操作之后,它的底层其实是这样的:

1
2
3
myObject.__proto__.a = 2;
myObject= {a:myObject.__proto__.a};
myObject.a = myObject.a + 1;

关于concat()方法连接数组和push()方法连接数组的区别

首先我们看一个例子:

1
2
3
4
5
6
7
8
var nums = [2, 3, 4, 5];
console.log(nums.concat([1, 2]))
//[2, 3, 4, 5, 1, 2]
console.log(nums)
//[2, 3, 4, 5]
nums.push([1, 2])
console.log(nums)
[2, 3, 4, 5, [1, 2]]

其实看了这个例子大家应该都懂了,首先,concat的作用是链接两个数组,会将两个数组拼合成一个数组,并且不会改变之前的数组的值,而是返回一个新数组.

push()则直接改变了数组的值,而且是直接将push()中传的参数直接接到了数组的后面,也就是当我们在push()中传参数组时,最后会得到一个嵌套的数组.

文章目录
  1. 1. 关于arguments的使用:
  2. 2. try/catch/finally的内容执行先后的问题
  3. 3. 关于全局的DOM变量
  4. 4. 关于属性的屏蔽
  5. 5. 关于concat()方法连接数组和push()方法连接数组的区别
|