最近做的测试题

整理一下最近做的一些比较有意思的测试题,大部分是js的

1.闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function test () {
var n = 4399;
function add () {
n++;
console.log(n);
}

return {
n: n,
add: add
}
}

var result = test();
var result2 = test();

result.add();
result.add();
console.log(result.n)
result2.add();

result两次调用add函数,每次使自身内部的n值加1,前两次输出为4400,4401
之后打印result上的n属性,因为是最初赋值的n,与闭包函数内部定义的变量n无关,输出4399
最后result2和result是独立的,互不影响,输出4400
最终结果是

1
2
3
4
4400
4401
4399
4400

2.函数声明

1
2
3
4
var f = function g() {
return 23;
};
console.log(typeof g());

我的第一反应就是,结果明显是’number’,仔细看了看,f是以一个匿名函数做的函数声明,实际上是没有g这个函数方法的,所以最终结果是

1
ReferenceError,g is not defined

3.数组长度

1
2
3
4
5
6
7
var arr = [];
arr[0] = 0;
arr[1] = 1;
arr.foo = 'c';
arr[3] = 3;

console.log(arr.length);

讲道理我之前还没见过这种给数组设置属性值的操作,不过数组的本质也是对象,直接设置属性也可以,并不会出错,最后生成的数组为[0, 1, empty, 3], length为4

4.类型转换

1
2
3
console.log( ([]) ? true : false ); 
console.log( ( [] == false ? true : false ) );
console.log( ( {} == false ) ? true : false );

首先需要明确的几点:

  • [] 和 {} 为 true
  • 在进行比较比较运算时,会进行强制类型转换
  • 在进行强制类型转换后,[]结果为0, {}结果为NaN

所以上述代码也可以看作

1
2
3
console.log( true ? true : false );
console.log( 0 == 0 ? true : false );
console.log( NaN == 0 ? true : false);

最终结果为

1
2
3
true
true
false

5.假设val已经声明,可定义为任何值

1
console.log('Value is ' + (val != '0') ? 'define' : 'undefine');

这道题我的答案是

1
2
Value is define
Value is undefine

然而并没有这么简单,问题只有一点,就是符号优先级的问题,+号是先于三目运算符进行运算的,所以最终结果是

1
define

6.异或和左移运算

1
2
3
4
5
function a (a) {
a ^= ( 1 << 4 ) - 1;
return a;
}
console.log(a(10));

首先是左移运算符: 1 << 4 将1转换为二进制数后向左移动4位,即 1 << 4 = 10000 = 16
那么执行a(10)之后进行的运算就相当于是 10 ^= 15,转换为二进制后进行按位异或运算

1
2
10 = 00001010
15 = 00001111

得到结果为: 00000101 = 5

7.变量声明赋值和作用域

1
2
3
4
5
6
7
8
9
10
var a,b;
(function(){
alert(a);
alert(b);
var a=b=3;
alert(a);
alert(b);
})();
alert(a);
alert(b);

第一组结果十分明显,由于变量a, b是全居变量,声明后未赋值,所以结果是undefined,undefined
第二组也很简单,变量a, b都被赋值为3,所以结果是3, 3
第三组把我坑到了,当进行 var a=b=3的赋值时,实际进行的操作为

1
2
b = 3;
var a = b;

将b作为全局变量进行赋值,而a是重新声明的,所以结果为undefined, 3

8.静态属性

1
2
3
4
5
6
7
8
9
10
class A{
public static $num = 0;
public function __construct(){
self::$num++;
}
}
new A();
new A();
new A();
echo A::$num;

如果$num不是static属性的话,结果应该是0,每次实例化A时$num值都不会影响,但是static属性常驻内存,不会被立即删除,所以输出是 3

9.this指向

1
2
3
4
5
6
7
8
9
10
11
var color = 'green';
var obj = {
color: 'blue',
getColor: function () {
color = 'red';
console.log(this.color);
}
}
var getColor = obj.getColor;
getColor();
obj.getColor();

js中的this关键字指向的是调用方法的对象,在声明之后使用getColor()方法调用,this指向window对象,而在方法调用时,全局的color被重新赋值为red,对象调用时,this指向自身的属性,所以输出结果为

1
2
red
blue

10.运算符和类型转换

1
2
3
4
console.log(1+ "2" + "2");
console.log(1 + +"2" + "2");
console.log("A" - "B" + "2");
console.log("A" - "B" + 2);

这里用到的几个知识点:

  • 在与字符串进行加法运算时,会将其他类型转换为字符串
  • 一元加运算符,会将变量转换为数字类型
  • 进行减法运算时,强制转换为数字进行运算

所以上面的计算过程

1
2
3
4
1 + "2" + "2" = "12" + "2" = "122"
1 + +"2" + "2" = 1 + 2 + "2" = 3 + "2" = 32
"A" - "B" + "2" = NaN + "2" = "NaN2"
"A" - "B" + 2 = NaN + 2 = NaN

11.变量引用与作用域

1
2
3
for (var i = 0; i < 10; i++) { 
setTimeout(function() { console.log(i); }, 100);
}

看到上面这段代码,有js基础的童鞋应该都明白,输出的结果应该是10个10,而不是0-9,因为每次定时器函数执行时,拿到的是同一个i值,那么如何顺利的输出想要的结果呢

1
2
3
4
5
for (var i = 0; i < 10; i++) { 
(function(i) {
setTimeout(function() { console.log(i); }, 100);
})(i);
}

用自调用函数来分割函数作用域,每次执行拿到的都是单独作用域中的i值,这样就可以输出0-9了

To Be Continue

文章目录
|