整理一下最近做的一些比较有意思的测试题,大部分是js的
1.闭包1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function 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
44400
4401
4399
4400
2.函数声明1
2
3
4var 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
7var 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
3console.log( ([]) ? true : false );
console.log( ( [] == false ? true : false ) );
console.log( ( {} == false ) ? true : false );
首先需要明确的几点:
- [] 和 {} 为 true
- 在进行比较比较运算时,会进行强制类型转换
- 在进行强制类型转换后,[]结果为0, {}结果为NaN
所以上述代码也可以看作1
2
3console.log( true ? true : false );
console.log( 0 == 0 ? true : false );
console.log( NaN == 0 ? true : false);
最终结果为1
2
3true
true
false
5.假设val已经声明,可定义为任何值1
console.log('Value is ' + (val != '0') ? 'define' : 'undefine');
这道题我的答案是1
2Value is define
Value is undefine
然而并没有这么简单,问题只有一点,就是符号优先级的问题,+号是先于三目运算符进行运算的,所以最终结果是1
define
6.异或和左移运算1
2
3
4
5function 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
210 = 00001010
15 = 00001111
得到结果为: 00000101 = 5
7.变量声明赋值和作用域1
2
3
4
5
6
7
8
9
10var 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
2b = 3;
var a = b;
将b作为全局变量进行赋值,而a是重新声明的,所以结果为undefined, 3
8.静态属性1
2
3
4
5
6
7
8
9
10class 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
11var 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
2red
blue
10.运算符和类型转换1
2
3
4console.log(1+ "2" + "2");
console.log(1 + +"2" + "2");
console.log("A" - "B" + "2");
console.log("A" - "B" + 2);
这里用到的几个知识点:
- 在与字符串进行加法运算时,会将其他类型转换为字符串
- 一元加运算符,会将变量转换为数字类型
- 进行减法运算时,强制转换为数字进行运算
所以上面的计算过程1
2
3
41 + "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
3for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100);
}
看到上面这段代码,有js基础的童鞋应该都明白,输出的结果应该是10个10,而不是0-9,因为每次定时器函数执行时,拿到的是同一个i
值,那么如何顺利的输出想要的结果呢1
2
3
4
5for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 100);
})(i);
}
用自调用函数来分割函数作用域,每次执行拿到的都是单独作用域中的i值,这样就可以输出0-9了
To Be Continue