基础面试题
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
主要内容包括:HTML,CSS,JavaScript,浏览器,性能优化等等
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(String(‘A’));
// A. Case A
// B. Case B
// C. Do not know!
// D. undefined
答案显然是A。与上面唯一不同的是没有使用 new 关键字,所以直接返回字符串,实际上,typeof string(A) === string 的结果是 true。解释参见第9条的解释。
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,求余运算符会保留符号,所以只有 isEven 的判断是可靠的。
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,这个在第一个问题中解释的很清楚了。
手机上刷题 更方便
=============
=======================================================================================================================================================================================================
13. 数组原型是数组
================
Array.isArray( Array.prototype )
// A. true
// B. false
// C. error
// D. other
答案是A。一个鲜为人知的事实:其实 Array.prototype 也是一个数组。这点在MDN文档中提到过。参考资料:
- MDN:Array.isArray()
14. 一言难尽的强制转换
==================
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log(wut);
}
// A. true
// B. false
// C. wut
// D. other
答案是B。这个是JavaScript中强制转换的经典案例,关于强制转换不是一两句话可以跟你说清楚的,我建议你系统性的学习一下,推荐你看看《你不知道的JavaScript-中卷》这本书,如果不舍得买书,github上有英文原版:You-Dont-Know-JS,深入理解之后你就是高手了。好了,回到当前这个问题。当 [0] 需要被强制转成 Boolean 的时候会被认为是 true。所以进入第一个 if 语句,而 a == true 的转换规则在ES5规范的第11.9.3节中已经定义过,你可以自己详细探索下。规范指出,== 相等中,如果有一个操作数是布尔类型,会先把他转成数字,所以比较变成了 [0] == 1;同时规范指出如果其他类型和数字比较,会尝试把这个类型转成数字再进行宽松比较,而对象(数组也是对象)会先调用它的 toString() 方法,此时 [0] 会变成 0,然后将字符串 0 转成数字 0,而 0 == 1 的结果显然是 false。参考资料:
-
ES5规范:11.9.3
-
《你不知道的JavaScript-中卷》
15. 撒旦之子“==”
=================
[]==[]
// A. true
// B. false
// C. error
// D. other
答案是B。ES5规范11.9.3.1-f指出:如果比较的两个对象指向的是同一个对象,就返回 true,否则就返回 false,显然,这是两个不同的数组对象。参考资料:
-
ES5规范:11.9.3.1
-
《你不知道的JavaScript-中卷》
16. 加号 VS 减号
=================
‘5’ + 3;
‘5’ - 3;
// A. 53, 2
// B. 8, 2
// C. error
// D. other
答案是A。5 + 2 = 52 很好理解,+ 运算符中只要有一个是字符串,就会变成字符串拼接操作。你不知道的是,- 运算符要求两个操作数都是数字,如果不是,会强制转换成数字,所以结果就变成了 5 - 2 = 3。参考资料:
- 《你不知道的JavaScript-中卷》,第四章:4.4.2 字符串和数字之间的隐式强制类型转换
17. 打死那个疯子
===============
1 + - + + + - + 1
// A. 2
// B. 1
// C. error
// D. other
答案是A。这个只能出现在示例代码中,如果你发现哪个疯子写了这个在生产代码中,打死他就行了。你只要知道 + 1 = 1和- 1 = -1,注意符号之间的空格。两个减号抵消,所以最终结果等效于 1 + 1 = 2。或者你也可以在符号之间插入 0 来理解,即 1 + 0 - 0 + 0 + 0 + 0 - 0 + 1,这样你就一目了然了吧!千万别写这样的代码,因为可能会被打死!
手机上刷题 更方便
=============
=======================================================================================================================================================================================================
18. 淘气的map
===============
var ary = Array(3);
ary[0] = 2;
ary.map(function(elem) {
return 1;
});
// A. [2, 1, 1]
// B. [1, 1, 1]
// C. [2, 1, 1]
// D. other
答案是D。实际上结果是 [1, undefined x 2],因为规范写得很清楚:
map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值组合起来形成一个新数组。callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。
参考资料:
- MDN: Array.prototype.map()
19. 统统算我的
==============
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a, b, c) {
c = 10;
sidEffecting(arguments);
return a + b + c;
}
bar(1, 1, 1);
// A. 3
// B. 12
// C. error
// D. other
答案是D。实际上结果是 21。在JavaScript中,参数变量和 arguments 是双向绑定的。改变参数变量,arguments 中的值会立即改变;而改变 arguments 中的值,参数变量也会对应改变。
20. 损失精度的IEEE 754
======================
var a = 111111111111111110000;
var b = 1111;
console.log(a + b);
// A. 111111111111111111111
// B. 111111111111111110000
// C. NaN
// D. Infinity
答案是B。这是IEEE 754规范的黑锅,不是JavaScript的问题。表示这么大的数占用过多位数,会丢失精度,学过计算机组成原理的应该知道是怎么回事。参考资料:
- Wiki:Double-precision floating-point format
手机上刷题 更方便
=============
=======================================================================================================================================================================================================
21. 反转世界
=============
var x = [].reverse;
x();
// A. []
// B. undefined
// C. error
// D. window
答案是D。MDN规范关于 reverse 的描述:
reverse 方法颠倒数组中元素的位置,并返回该数组的引用。
而这里调用的时候没有制定数组,所以默认的 this 就是 window,所以最后结果返回的是 window。参考资料:
- MDN:Array.prototype.reverse()
22. 最小的正值
==============
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。
因为 MIN_VALUE是 Number 的一个静态属性,因此应该直接使用:Number.MIN_VALUE,而不是作为一个创建的 Number实例的属性。
参考资料:
- MDN:Number.MIN_VALUE
23. 谨记优先级
==============
[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。同理可以分析后者。参考资料:
- MDN:运算符优先级
24. 坑爹中的战斗机
================
// the most classic wtf
2 == [[[2]]]
// A. true
// B. false
// C. undefined
// D. other
答案是A。根据ES5规范,如果比较的两个值中有一个是数字类型,就会尝试将另外一个值强制转换成数字,再进行比较。而数组强制转换成数字的过程会先调用它的 toString方法转成字符串,然后再转成数字。所以 [2]会被转成 2,然后递归调用,最终 [[[2]]] 会被转成数字 2。
25. 小数点魔术
==============
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(),人为加上括号,这就是合法的。
26. 自动提升为全局变量
==================
(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 声明过,所以在函数外部是无法访问的。
27. 正则表达式实例
================
var a = /123/;
var b = /123/;
a == b;
a === b;
// A. true, true
// B. true, false
// C. false, false
// D. other
答案是C。每个字面的正则表达式都是一个单独的实例,即使它们的内容相同。
28. 数组也爱比大小
================
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 按照字典序进行比较了(你若不信,可以重现两个变量的 toString 方法,进行测试)。
手机上刷题 更方便
=============
=======================================================================================================================================================================================================
29. 原型把戏
=============
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 方法来获取一个对象的原型。
30. 构造函数的函数
================
function f() {}
var a = f.prototype;
var b = Object.getPrototypeOf(f);
a === b;
// A. true
// B. false
// C. null
// D. other
答案是B。这个解释起来有点绕口,我们先来看另外一段代码:
function Person() {}
var p = new Person();
var a = p.proto;
var b = Object.getPrototypeOf§;
var c = Person.prototype;
console.log(a === b, a === c, b === c);
// true, true, true
var d = Person.proto;
var e = Object.getPrototypeOf(Person);
var f = Function.prototype;
console.log(d === e, d === f, e === f);
// true, true, true
首先你要明白,任何函数都是 Function 的实例,而p是函数 Person 的实例,Object.getPrototypeOf 会获取构造当前对象的原型。所以 Object.getPrototypeOf§ === Person.prototype,而 Object.getPrototypeOf(Person) === Function.prototype,所以答案就很明显了。我解释的不是很好,如果读者有更好的解释,欢迎评论。
31. 禁止修改函数名
================
function foo() {}
var oldName = foo.name;
foo.name = bar;
[oldName, foo.name];
// A. error
// B. [, ]
// C. [foo, foo]
// D. [foo, bar]
答案是C。函数名是禁止修改的,规范写的很清楚,所以这里的修改无效。参考资料:
- MDN:Function.name
32. 替换陷阱
=============
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),结果你就懂了。参考资料:
- MDN:String.prototype.replace()
33. 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
答案是C。根据第30题的解释,我们知道代码中的 parent 实际上就是 Function.prototype,而它在控制台中输出为:
function () {
[native code]
}
它的 name 属性是 ,所以你 eval()是得不到任何东西的。
手机上刷题 更方便
=============
=======================================================================================================================================================================================================
34. 正则测试陷阱
===============
var lowerCaseOnly = /1+$/;
[lowerCaseOnly.test(null), lowerCaseOnly.test()]
// A. [true, false]
// B. error
// C. [true, true]
// D. [false, true]
答案是C。test 方法的参数如果不是字符串,会经过抽象 ToString操作强制转成字符串,因此实际上测试的是字符串 null 和 undefined。
35. 逗号定义数组
===============
[,].join(, )
// A. , , ,
// B. undefined, undefined, undefined, undefined
// C. , ,
// D.
答案是C。JavaScript允许用逗号来定义数组,得到的数组是含有3个 undefined 值的数组。MDN关于 join 方法的描述:
所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是undefined 或者null, 则会转化成空字符串。
参考资料:
- MDN:Array.prototype.join()
36. 保留字 class
==================
var a = {class: Animal, name: Fido};
console.log(a.class);
// A. Animal
// B. Object
// C. an error
// D. other
答案是D。实际上真正的答案取决于浏览器。class 是保留字,但是在Chrome、Firefox和Opera中可以作为属性名称,在IE中是禁止的。另一方面,其实所有浏览器基本接受大部分的关键字(如:int、private、throws等)作为变量名,而class是禁止的。
37. 无效日期
=============
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。
38. 神鬼莫测的函数长度
==================
var a = Function.length;
var b = new Function().length;
console.log(a === b);
// A. true
// B. false
// C. error
// D. other
答案是B。实际上a的值是1,b的值是0。还是继续来看MDN文档关于 Function.length 的描述吧!Function构造器的属性:
Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true。
Function原型对象的属性:
Function原型对象的 length 属性值为 0 。
所以,在本例中,a代表的是 Function 构造器的 length 属性,而b代表的是 Function 原型的 length 属性。参考资料:
- MDN:Function.length
39. Date的面具
================
文末
如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。
同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。
这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。
269页《前端大厂面试宝典》
包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
前端面试题汇总
JavaScript
var b = new Function().length;
console.log(a === b);
// A. true
// B. false
// C. error
// D. other
答案是B。实际上a的值是1,b的值是0。还是继续来看MDN文档关于 Function.length 的描述吧!Function构造器的属性:
Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true。
Function原型对象的属性:
Function原型对象的 length 属性值为 0 。
所以,在本例中,a代表的是 Function 构造器的 length 属性,而b代表的是 Function 原型的 length 属性。参考资料:
- MDN:Function.length
39. Date的面具
================
文末
如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。
同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。
这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。
269页《前端大厂面试宝典》
包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
前端面试题汇总
JavaScript
a-z ↩︎