0
点赞
收藏
分享

微信扫一扫

前端笔试题(基础34题)

1.下面代码输出是什么?

const anArray = [1, 2, 3, 4, 5];
anArray[10] = 100;
console.log(anArray);

结果为 [1, 2, 3, 4, 5, empty × 5, 100]
如果你为数组中的索引设置的值超过了数组的长度,则JavaScript将创建其中包含未定义值的“空数”。

2.下面代码输出是什么?

let arr =[1, 2, 3, 4, 5].map((n) => {
  if (n < 10) return;
  return n * 2;
});
console.log(arr)

打印结果:[undefined, undefined, undefined, undefined, undefined]
在此题目中,如果n <10,则不返回值,而在函数中不返回值时,则返回“ undefined”。在这种情况下,对于数组中的每个元素,map函数都会返回“ undefined”,所以结果集合是一个充满“ undefined”的数组。

3.parseInt 遇上 map

["1", "2", "3"].map(parseInt)

// A. ["1", "2", "3"]
// B. [1, 2, 3]
// C. [0, 1, 2]
// D. other

答案是D。实际上返回的结果是 [1, NaN, NaN] ,因为 parseInt 函数只需要两个参数 parseInt(value, radix) ,而 map 的回调函数需要三个参数 callback(currentValue, index, array)。
MDN文档中指明 parseInt 第二个参数是一个2到36之间的整数值,用于指定转换中采用的基数。如果省略该参数或其值为0,则数字将以10为基础来解析。
如果该参数小于2或者大于36,则 parseInt 返回 NaN。此外,转换失败也会返回 NaN。
现在来分析问题。parseInt("1", 0) 的结果是当作十进制来解析,返回 1;parseInt("2", 1) 的第二个参数非法,返回 NaN;parseInt("3", 2) 在二进制中,"3" 是非法字符,转换失败,返回 NaN。

4.神奇的null

[typeof null, null instanceof Object]
// A. ["object", false]
// B. [null, false]
// C. ["object", true]
// D. other

答案是A。在MDN关于 null 的文档中也特别指出来了,typeof null 的结果是 "object",它是ECMAScript的bug,其实应该是 "null"。但这个bug由来已久,在JavaScript中已经存在了将近二十年,也许永远不会修复,因为这牵扯到太多的Web系统,修复它会产生更多的bug,令许多系统无法正常工作。而 instanceof 运算符是用来测试一个对象在其原型链构造函数上是否具有 prototype 属性,null 值并不是以 Object 原型创建出来的,所以 null instanceof Object 返回 false。

5.该死的优先级

var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
// A. Value is Something
// B. Value is Nothing
// C. NaN
// D. other

答案是D。实际上输出 "Something",因为 + 的优先级比条件运算符 condition ? val1 : val2 的优先级高。

6.神鬼莫测之变量提升

var name = 'World!';
(function () {
    if (typeof name === 'undefined') {
      var name = 'Jack';
      console.log('Goodbye ' + name);
    } else {
      console.log('Hello ' + name);
    }
})();

// A. Goodbye Jack
// B. Hello Jack
// C. Hello undefined
// D. Hello World

答案是A,在 JavaScript中, functions 和 variables 会被提升。变量提升是JavaScript将声明移至作用域 scope (全局域或者当前函数作用域) 顶部的行为。
所以,上面的代码与下面这段代码是等价的:

var name = 'World!';
(function () {
    var name;
    if (typeof name === 'undefined') {
      name = 'Jack';
      console.log('Goodbye ' + name);
    } else {
      console.log('Hello ' + name);
    }
})();

7.死循环陷阱

var END = Math.pow(2, 53);
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) { 
  count++;
}
console.log(count);

// A. 0
// B. 100
// C. 101
// D. other

答案是D。在JavaScript中,2^53 是最大的值,没有比这更大的值了。所以 2^53 + 1 == 2^53,所以这个循环无法终止。

8.过滤器魔法

var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) {
  return x === undefined;
});

// A. [undefined x 7]
// B. [0, 1, 2, 10]
// C. []
// D. [undefined]

答案是C。
filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

9.警惕IEEE 754标准

var two = 0.2;
var one = 0.1;
var eight = 0.8;
var six = 0.6;
[two - one == one, eight - six == two]

// A. [true, false]
// B. [false, false]
// C. [true, false]
// D. other

答案是C。JavaScript中采用双精度浮点数格式,即IEEE 754标准。在该格式下,有些数字无法表示出来,比如:0.1 + 0.2 = 0.30000000000000004 ,这不是JavaScript的锅,所有采用该标准的语言都有这个问题,比如:Java、Python等。

10.字符串陷阱

function showCase(value) {
  switch(value) {
    case 'A':
      console.log('Case A');
      break;
    case 'B':
      console.log('Case B');
      break;
    case undefined:
      console.log('undefined');
      break;
    default:
      console.log('Do not know!');
  }
}
showCase(new String('A'));

// A. Case A
// B. Case B
// C. Do not know!
// D. undefined

答案是C。在 switch 内部使用严格相等 === 进行判断,并且 new String("A") 返回的是一个对象,而 String("A") 则是直接返回字符串 "A"。
不使用new关键字,则答案是A

11.并非都是奇偶

function isOdd(num) {
  return num % 2 == 1;
}

function isEven(num) {
  return num % 2 == 0;
}

function isSane(num) {
  return isEven(num) || isOdd(num);
}

var values = [7, 4, "13", -9, Infinity];
values.map(isSane);

// A. [true, true, true, true, true]
// B. [true, true, true, true, false]
// C. [true, true, true, false, false]
// D. [true, true, false, false, false]

答案是C。-9 % 2 = -1 以及 Infinity % 2 = NaN,求余运算符会保留符号

12.parseInt小贼

parseInt(3, 8);
parseInt(3, 2);
parseInt(3, 0);

// A. 3, 3, 3
// B. 3, 3, NaN
// C. 3, NaN, NaN
// D. other

答案是D。实际结果是 3, NaN, 3
parseInt的第一个参数是必需,要被解析的字符串。
第二个参数可选,表示要解析的数字的基数。该值介于 2 ~ 36 之间。
如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。
如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。

13.数组原型是数组

Array.isArray(Array)
Array.isArray( Array.prototype )

打印结果是 false true,Javascript就是这么神奇

14.一言难尽的强制转换

console.log(Boolean([0]));
console.log([0] == true);
console.log("0" == true);

打印结果是
true,false,fasle
当 [0] 需要被强制转成 Boolean 的时候会被认为是 true。
== 相等中,如果有一个操作数是布尔类型,会先把他转成数字,所以比较变成了 [0] == 1;同时规范指出如果其他类型和数字比较,会尝试把这个类型转成数字再进行宽松比较,而对象(数组也是对象)会先调用它的 toString() 方法,此时 [0] 会变成 "0",然后将字符串 "0" 转成数字 0,而 0 == 1 的结果显然是 false。

15.损失精度的IEEE 754

var a = 111111111111111110000;
var b = 1111;
console.log(a + b);

// A. 111111111111111111111
// B. 111111111111111110000
// C. NaN
// D. Infinity

答案是B。这是IEEE 754规范的黑锅,不是JavaScript的问题。表示这么大的数占用过多位数,会丢失精度,学过计算机组成原理的应该知道是怎么回事。

16.最小的正值

Number.MIN_VALUE > 0

// A. false
// B. true
// C. error
// D. other

答案是B。
MIN_VALUE属性是 JavaScript 里最接近 0 的正值,而不是最小的负值。
MIN_VALUE的值约为 5e-324。小于 MIN_VALUE
("underflow values") 的值将会转换为 0。

17.谨记优先级

[1 < 2 < 3, 3 < 2 < 1]

// A. [true, true]
// B. [true, false]
// C. error
// D. other

答案是A。<和>的优先级都是从左到右,所以 1 < 2 < 3 会先比较 1 < 2,这会得到 true,但是 < 要求比较的两边都是数字,所以会发生隐式强制转换,将 true 转换成 1,所以最后就变成了比较 1 < 3,结果显然为 true。同理可以分析后者。

18.和数字进行比较

2 == [[[2]]]

// A. true
// B. false
// C. undefined
// D. other

答案是A。根据ES5规范,如果比较的两个值中有一个是数字类型,就会尝试将另外一个值强制转换成数字,再进行比较。而数组强制转换成数字的过程会先调用它的 toString方法转成字符串,然后再转成数字。所以 [2]会被转成 "2",然后递归调用,最终 [[[2]]] 会被转成数字 2。

19.小数点魔术

3.toString();
3..toString();
3...toString();

// A. "3", error, error
// B. "3", "3.0", error
// C. error, "3", error
// D. other

答案是C。点运算符会被优先识别为数字常量的一部分,然后才是对象属性访问符。所以 3.toString() 实际上被JS引擎解析成 (3.)toString(),显然会出现语法错误。但是如果你这么写 (3).toString(),人为加上括号,这就是合法的。

20.自动提升为全局变量

(function() {
  var x = y = 1;
})();
console.log(y);
console.log(x);

// A. 1, 1
// B. error, error
// C. 1, error
// D. other

答案是C。很经典的例子,在函数中没有用 var 声明变量 y,所以 y 会被自动创建在全局变量 window下面,所以在函数外面也可以访问得到。而 x 由于被 var 声明过,所以在函数外部是无法访问的

21.正则表达式实例

var a = /123/;
var b = /123/;
a == b;
a === b;

// A. true, true
// B. true, false
// C. false, false
// D. other

答案是C。每个字面的正则表达式都是一个单独的实例,即使它们的内容相同。

22.数组比大小

var a = [1, 2, 3];
var b = [1, 2, 3];
var c = [1, 2, 4];

a == b;
a === b;
a > c;
a < c;

// A. false, false, false, true
// B. false, false, false, false
// C. true, true, false, true
// D. other
```答案是A。数组也是对象,ES5规范指出如果两个对象进行相等比较,只有在它们指向同一个对象的情况下才会返回 true,其他情况都返回 false。而对象进行大小比较,会调用 toString 方法转成字符串进行比较,所以结果就变成了字符串 "1,2,3" 和 "1,2,4" 按照字典序进行比较了

### 23,原型把戏

var a = {};
var b = Object.prototype;

[a.prototype === b, Object.getPrototypeOf(a) == b]

// A. [false, true]
// B. [true, true]
// C. [false, false]
// D. other

答案是A。对象是没有 prototype 属性的,所以 a.prototype 是 undefined,但我们可以通过 Object.getPrototypeOf 方法来获取一个对象的原型。

### 24.构造函数的函数

function Person() {}
var p = new Person();

var a = p.proto;
var b = Object.getPrototypeOf(p);
var c = Person.prototype;
console.log(a === b, a === c, b === c);

var d = Person.proto;
var e = Object.getPrototypeOf(Person);
var f = Function.prototype;
console.log(d === e, d === f, e === f);

function f() {}
var a = f.prototype;
var b = Object.getPrototypeOf(f);
console.log(a === b);

答案是
true, true, true
true, true, true
false
任何函数都是 Function 的实例,而p是函数 Person 的实例,Object.getPrototypeOf 会获取构造当前对象的原型。所以 Object.getPrototypeOf(p) === Person.prototype,而 Object.getPrototypeOf(Person) === Function.prototype,所以答案就很明显了。

### 25.禁止修改函数名

function foo() {}
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name];

["foo", "foo"],函数名是禁止修改的,所以这里的修改无效。

### 26.替换陷阱

"1 2 3".replace(/\d/g, parseInt);

// A. "1 2 3"
// B. "0 1 2"
// C. "NaN 2 3"
// D. "1 NaN 3"

答案是D。如果 replace 方法第二个参数是一个函数,则会在匹配的时候多次调用,第一个参数是匹配的字符串,第二个参数是匹配字符串的下标。所以变成了调用 parseInt(1, 0)、parseInt(2, 2)和parseInt(3, 4),结果你就懂了。

### 27.Function的名字

function f() {}
var parent = Object.getPrototypeOf(f);
console.log(f.name);
console.log(parent.name);
console.log(typeof eval(f.name));
console.log(typeof eval(parent.name));

// A. "f", "Empty", "function", "function"
// B. "f", undefined, "function", error
// C. "f", "Empty", "function", error
// D. other

parent 实际上就是 Function.prototype,而它在控制台中输出为:

function () {
[native code]
}

它的 name 属性是 "",所以 eval("")是得不到任何东西的。

### 28.正则测试陷阱

var lowerCaseOnly = /^[a-z]+$/;
[lowerCaseOnly.test(null), lowerCaseOnly.test()]

// A. [true, false]
// B. error
// C. [true, true]
// D. [false, true]

答案是C。test 方法的参数如果不是字符串,会经过抽象 ToString操作强制转成字符串,因此实际上测试的是字符串 "null" 和 "undefined"。

### 29.逗号定义数组

[,,,].join(", ")

// A. ", , , "
// B. "undefined, undefined, undefined, undefined"
// C. ", , "
// D. ""

答案是C。JavaScript允许用逗号来定义数组,得到的数组是含有3个 undefined 值的数组。MDN关于 join 方法的描述:
> 所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是undefined 或者null, 则会转化成空字符串。

### 30.无效日期

var a = new Date("epoch");

// A. Thu Jan 01 1970 01:00:00 GMT+0100(CET)
// B. current time
// C. error
// D. other

答案是D。实际结果是 Invalid Date,它实际上是一个Date对象,因为 a instance Date 的结果是 true,但是它是无效的Date。Date对象内部是用一个数字来存储时间的,在这个例子中,这个数字是 NaN。

### 31.Date的面具

var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c];

// A. [true, true, true]
// B. [false, false, false]
// C. [false, true, false]
// D. [true, false, false]

答案是B。
只能通过调用 Date 构造函数来实例化日期对象:以常规函数调用它(即不加 new 操作符)将会返回一个字符串,而不是一个日期对象。另外,不像其他JavaScript 类型,Date 对象没有字面量格式
所以a是表示当前日期的字符串,传入参数是无效的,b和c是Date对象,并且b代表的是1970年那个初始化时间,而c代表的是当前时间。

### 32.min与max

var min = Math.min();
var max = Math.max();
console.log(min < max);

// A. true
// B. false
// C. error
// D. other

Math.min()和Math.max()接收一组数值为参数,如果有任一参数不能被转换为数值,结果为NaN
答案是B。看MDN文档,对 Math.min的描述:
如果没有参数,结果为Infinity。
对 Math.max 的描述:
如果没有参数,结果为-Infinity。

### 33.不同的日期

var a = new Date("2014-03-19");
var b = new Date(2014, 03, 19);
[a.getDay() == b.getDay(), a.getMonth() == b.getMonth()]

// A. [true, true]
// B. [true, false]
// C. [false, true]
// D. [false, false]

a和b表示的不同月份的时间
所以答案是D,关于Date还需要特别注意的一点:
> 当Date作为构造函数调用并传入多个参数时,如果数值大于合理范围时(如月份为13或者分钟数为70),相邻的数值会被调整。比如 new Date(2013, 13, 1)等于new Date(2014, 1, 1),它们都表示日期2014-02-01(注意月份是从0开始的)。其他数值也是类似,new Date(2013, 2, 1, 0, 70)等于new Date(2013, 2, 1, 1, 10),都表示时间2013-03-01T01:10:00。

### 34.匹配隐式转换

if("http://giftwrapped.com/picture.jpg".match(".gif")) {
console.log("a gif file");
} else {
console.log("not a gif file");
}

// A. "a gif file"
// B. "not a gif file"
// C. error
// D. other

答案是A。看MDN对 match 方法的描述:
如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj)
将其转换为正则表达式对象。
所以我们的字符串 ".gif" 会被转换成正则对象 /.gif/,会匹配到 "/gif"。

### 35.重复声明变量

function foo(a) {
var a;
return a;
}

function bar(a) {
var a = "bye";
return a;
}

[foo("hello"), bar("hello")]

// A. ["hello", "hello"]
// B. ["hello", "bye"]
// C. ["bye", "bye"]
// D. other

答案是B。一个变量在同一作用域中已经声明过,会自动移除 var 声明,但是赋值操作依旧保留,结合前面提到的变量提升机制,你就明白了。

### 36.下面代码会输出什么?

var fullname = "1";
var obj = {
fullname: "2",
prop: {
fullname: "3",
//如果改成普通函数呢?
getFullname: () => {
return this.fullname;
},
},
};
console.log(obj.prop.getFullname());
var test = obj.prop.getFullname;
console.log(test());

如果把箭头函数换成普通函数呢?
箭头函数 1,1
普通函数3,1

### 37.下面的代码会输出什么?

const o1 = {
text: "o1",
fn: function () {
return this.text;
},
};
const o2 = {
text: "o2",
fn: function () {
return o1.fn();
},
};
const o3 = {
text: "o3",
fn: function () {
var fn = o1.fn;
return fn();
},
};
console.log(o1.fn()); //o1
console.log(o2.fn()); //o1
console.log(o3.fn()); //o3

答案:
o1,o1,undefined

### 38.下面的代码会输出什么?

var a = 20;
var test = {
a: 40,
init: () => {
console.log(this.a);
function go() {
console.log(this.a);
}
go.prototype.a = 50;
return go;
}
};

var p = test.init();
p();
new p()

答案是:
20,20,50

### 37.解释下下面两段代码执行结果的差异

function foo() {
foo();
}
function foo() {
setTimeout(() => {
foo();
}, 0)
}

上面的执行结果,代码会报错Maximum call stack size exceeded,堆栈溢出,因为无数的foo都会在调用栈中堆积。
下面的foo不会报错,因为setTimeout在任务队列会被不断的推到执行队列,所以堆栈不会溢出,但是foo函数会一直循环执行。

### 38.下面代码会输出什么

console.log('A')
while (true) {}
console.log('B')

上面这段代码只会打印出来a,while是同步任务,会不断的循环,所以打印不出b
举报

相关推荐

0 条评论