JavaScript经典笔试题
1.下面程序的运行结果是(函数参数,Arguments 对象)
function test(x, y, z) {
alert(test.length);
alert(arguments.length);
alert(arguments.callee === test);
alert(arguments[2]);
}
test(10, 20);
A.2,3,true,0 B.3,3,false,20 C.3,2,true,undefined D.2,3,false,10
分析:test.length是返回的函数的形参个数,所以为3;arguments.length返回的是函数调用时的实参个数,所以为2;arguments.callee:初始值就是正被执行的 Function 对象,用于在函数内部调用自身,特别是函数本身为匿名函数时,要在内部调用自己,那么它就闪亮登场了,arguments对象本身是个由函数调用时传入的实参组成的伪数组,访问单个参数的方式与访问数组元素的方式相同。索引 n 实际上是 arguments 对象的 0…n 属性的其中一个参数。由于调用test时,没有传入第三个参数,所以返回undefined
扩展:谈到arguments,在说说它的另一个应用,刚才谈到arguments.length返回的是函数调用时的实参个数,那么通过判断这个实参个数,我们就可以优雅的模拟实现js的”重载“了
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 5);
} else if(arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //输出 "15"
doAdd(40, 20); //输出 "60"
当只有一个参数时,doAdd() 函数给参数加 5。如果有两个参数,则会把两个参数相加,返回它们的和。所以,doAdd(10) 输出的是 "15",而 doAdd(40, 20) 输出的是 "60"。虽然不如重载那么好,不过已足以避开 ECMAScript 的这种限制。
- 下面程序的运行结果是(作用域,变量提升)
var x = 30;
function test(){
alert(x);
var x = 10;
alert(x);
x = 20;
function x() {};
alert(x);
}
test();
A.30,10,function x(){} B.undefined,10,20 C. function x(){},10,20 D. 30,10,20
分析:进入test函数,第一个alert(x)返回的是function x(){},为什么了?这个就要从js的预解析谈起了,进入函数的作用越后,js会首先读取变量和函数的声明,当变量和函数重名时(不管谁先谁后),函数名优先(具体的原因,我将稍后单独写一篇随笔)所以这个地方x指向了function x(){}。为什么不是外面的x=30了?因为在test函数的作用域里,能够找到x的声明,所以相当于内部x将外部的x给屏蔽了!执行第二个alert(x)时,前面一行已经给x赋值为10,所以为10;执行第三个alert(x)时,变量x已经被赋值为20了,那么function x(){}对x有什么影响了?没有任何影响,因为它就仅仅是个函数声明。所以为20
- 下面程序的运行结果是(闭包)
function test() {
var x = 10;
var y = 20;
return function () {
alert([x, y]);
};
}
var x = 30;
var y = 40;
var temp = test();
temp();
A.30,40 B.10,40 C.10,20 D.30,20
分析: 显示,通过temp此时已经是一个函数了,它相当于 temp = function(){ alert([x,y])}。此时关键是看x,y的值了,到底是指向test函数里里面的值了还是外面。
此处又涉及到了 闭包,即test内部的x,y没有释放,原因就是alert([x,y])引用了它,所以答案是 C
- 1), 2) ,3)的运行结果分别是(运算符)
- false == 0
- "5" + 3
3)"5" + {
toString: function(){return this;},
valueOf: function(){return "valueOf";}
}
A.true,"8","5this" B.false,8,"5valueOf"
C.true,"53","5valueOf" D.fasle,"53","5[object Objetc]"
分析:1中为true,因为==会执行一个类型自动转化,Number(false)的值为0,Boolean(0)的值为false;
2,“+”此时是做为链接符号存在的。ECMAScript262中规定,首先对"+"前后的两个表达式进行求值,即调用valueof方法。再调用typeof对他们的类型进行判断,如果有一个类型为string的则都将转化为string。所以后面的3会被转化为string类型。如果此处为“-”,则答案为2,会将前面的“5”转化为number类型
3,在2中已经说到,“+”后面的对象,首先会调用valueOf(),所以后面的对象的求值结果为“valueOf”,也是字符串。最后直接连接在一起。
5.下面输出的值是多少?(考察this)
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
输出:10 2
第一次输出10应该没有问题。我们知道取对象属于除了点操作符还可以用中括号,所以第二次执行时相当于arguments调用方法,this指向arguments,而这里传了两个参数,故输出arguments长度为2。
6.以下输出结果是多少?(var和函数的提前声明)
function fn(a) {
console.log(a);
var a = 2;
function a() {}
console.log(a);
}
fn(1);
输出:function a() {} 2
我们知道var和function是会提前声明的,而且function是优先于var声明的(如果同时存在的话),所以提前声明后输出的a是个function,然后代码往下执行a进行重新赋值了,故第二次输出是2。
7.以下输出结果是?(局部变量和全局变量)
var f = true;
if (f === true) {
var a = 10;
}
function fn() {
var b = 20;
c = 30;
}
fn();
console.log(a);
console.log(b);
console.log(c);
输出:10 报错 30
{...}内的新声明的变量不是局部变量(var 声明 let不成立,因为let有代码块域的存在),function内的新声明的变量才是局部变量,而没有用var声明的变量在哪里都是全局变量。再次提醒切记只有function(){}内新声明的才能是局部变量,while{...}、if{...}、for(..) 之内的都是全局变量(除非本身包含在function内)