此次列举出一些觉得有意思的 JS 题目(来源于出了名的 44 题), 相信有非常多关于这些题目的博客, 写这篇博客的目的在于巩固一些知识点, 希望能和读者共同进步.
1. map 函数执行过程
["1", "2", "3"].map(parseInt)
答案: [1, NaN, NaN]
解析: map(function callback(current, index, array)), map 回掉提供三个参数, current value, index of current value, array.
parseInt(value, radix), parseInt 提供两个参数, value 表示需要转换的 string,radix 表示 string 原本的进制单位, 从 2 到 36.
所以这道题的执行过程是这样的:
array.map(parseInt(value(current), radix(index) )); 回掉会自动按序分配参数
current => value, index => radix;
真实执行过程
array.map(parseInt(1, 0)) => parseInt(1, 0), 0 默认代表十进制.
parseInt(2, 1), 没有 1 进制, 所以返回 NaN,
parseInt(3,2), 2 进制只有 0,1, 所以同样返回 NaN
2.[typeof null, null instanceof Object]
答案: [object, false]
解析: typeof 返回一个表示类型的字符串, typeof null == object.
instanceof 用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性, 显而易见, null 没有构造函数, 所以返回的是 false
运算符优先级
- var val = 'smtg';
- console.log('Value is' + (val === 'smtg') ? 'Something' : 'Nothing')
答案: Something
解析:+ 运算符优先级高于> , 所以没有括号的情况下, 会先执行字符串连接操作.
所以等价于'Value is true'? 'Something' : 'Nothing'
如果搞不清运算符优先级的时候, 可以加上括号
稀疏数组与 Array.filter
- var ary = [0,1,2];
- ary[10] = 10;
- ary.filter(function(x) {
- return x === undefined;
- });
答案:[]
解析: 这边的 ary 是一个稀疏数组, index 从 3 到 9 都没有定义, 所以 ary[3~9]的值是 undefined(可以在 Chrome tool 里通过 ary[index]来查看), 那么乍一看这个题的答案应该是返回 7 个 undefined 组成的数组.
但是这里返回的是[], 原因在于 filter 函数的作用.
- if (!Array.prototype.filter){
- Array.prototype.filter = function(func, thisArg) {
- 'use strict';
- if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
- throw new TypeError();
- var len = this.length>>> 0,
- res = new Array(len), // preallocate array
- t = this, c = 0, i = -1; // 前端全栈学习交流圈: 866109386.
- if (thisArg === undefined){// 面相 1-3 年前端开发人员.
- while (++i !== len){ // 帮助突破技术瓶颈, 提升思维能力.
- // checks to see if the key was set
- // 看这里 看这里
- if (i in this){
- if (func(t[i], i, t)){
- res[c++] = t[i];
- }
- }
- }
- }
- else{
- while (++i !== len){
- // checks to see if the key was set
- if (i in this){
- if (func.call(thisArg, t[i], i, t)){
- res[c++] = t[i];
- }
- }
- }
- }
- res.length = c; // shrink down array to proper size
- return res;
- };
- }
可以看红色文字下方的代码, filter 函数会先判断当前 index 是否在数组中被设置, 即是否有 ary[index] = value 的过程, 否则会跳过这个 index.
所以对于稀疏数组, 未定义的 index 会被跳过, 从而导致这道题的答案是[]. 如果有 ary[index] = undefined, 那么结果就会是返回由 undefined 组成的数组.
5. String('A') 和 new String('A') 的区别
以下两个代码段的输出结果是?
- 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'));
- function showCase2(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!');
- }
- }
- showCase2(String('A'));
答案:'Do not know!' ; 'Case A'
解析: 为什么两个代码段的输出不一致呢?
两个原因: 1.switch 进行比较的时候用的是全等符 "===", 所以不会做类型转换, 即 "10" 不会等于 10;
new String() 和 String 返回的类型不同, 前者返回的是 object, 后者返回的是 string, 所以在做全等比较的时候, 返回的结果是 false.
所以如果有需要用到 switch 对于字符串做比较的时候, 需要注意传入的参数类型.
6. 你真的了解 "==" 吗?
下面两个代码段的输出是?
- var a = [0];
- if ([0]) {
- console.log(a == true);
- } else {
- console.log("wut");
- }
- []==[]
答案: false, false
解析: 如果单纯的把 [0] 转换成 boolean 类型的话, 结果会是 true, 所以 if 判断语句的结果是 true.
看了很多其他的博客, 都有说到 "==" 会做类型转换, 比较其值, 我觉得这个答案依然无法详细解释上述代码的结果.
查阅了更多资料后, 找到了一些 "==" 的规则:
1, 如果两个值类型相同, 进行 === 比较, 比较规则同上
2, 如果两个值类型不同, 他们可能相等. 根据下面规则进行类型转换再比较:
a, 如果一个是 null, 一个是 undefined, 那么[相等].
b, 如果一个是字符串, 一个是数值, 把字符串转换成数值再进行比较.
c, 如果任一值是 true, 把它转换成 1 再比较; 如果任一值是 false, 把它转换成 0 再比较.
d, 如果一个是对象, 另一个是数值或字符串, 把对象转换成基础类型的值再比较. 对象转换成基础类型, 利用它的 toString 或者 valueOf 方法. JS 核心内置类, 会尝试 valueOf 先于 toString; 例外的是 Date,Date 利用的是 toString 转换. 非 JS 核心的对象, 令说(比较麻烦, 我也不大懂)
e, 任何其他组合(array 数组等), 都不相等.
所以其实 "==" 的转换规则, 并没有想象的那么简单, 由此可见[0] == true, 应该采用的是规则 c, 而[] == [] 应该采用的是规则 e.
最后附上一张 "==" 比较的结果图
- 7. Arguments of methods
- function sidEffecting(ary) {
- ary[0] = ary[2];
- }
- function bar(a,b,c) {
- c = 10
- sidEffecting(arguments);
- return a + b + c;
- }
- bar(1,1,1)
- function sidEffecting(ary) {
- ary[0] = ary[2];
- }
- function bar(a,b,c) {
- c = 10
- sidEffecting(arguments);
- return a + b + c;
- }
- bar(1,1,1)
答案: 21, 12
解析: 第一个代码段的答案, 我相信很容易得出. 问题是第二个代码段, 乍一看结果应该和第一个代码段相同, 实则不然, 那么是为什么呢?
其实这边不同的结果是由 arguments 这个对象 (arguments 不是数组) 造成的, 如果函数的参数有默认值的时候, 那么 arguments 这个对象不会追踪参数值的变化, 并且只记录传递过来的值.
所以第二个代码段中, arguments 的结果是(1,1,1),sideEffecting 函数拿到的结果是 ary[0] =1, ary[2] =1; 所以回到 a+b+c = 1+1+10 ==》 12.
有趣的比较符又来了
[1 <2 < 3, 3 < 2 < 1]
答案: true, true
解析: 1<2<3 等价于 1<2=> true; true<3 => 1<3=> true;
3<2=> false; false<1 => 0<1=> true.
9. 变量提升
- (function(){
- var x = y = 1;
- })();
- console.log(y);
- console.log(x);
答案: 1, error
解析: 这道题目涉及到变量提升的范围, 以及赋值语法.
var x=y=1 等价于 var x=1; y=1; 这里的 y 会被提升至全局域, 所以的除上述答案.
var x=1,y=1 等价于 var x=1; var y=1, 这样写的话, x,y 都是局部变量, 不会被提升.
先总结这么几道, 之后碰到觉得有趣的题目, 会持续更新.
来源: http://www.qdfuns.com/article/51070/74feae486e16a1690aba8b6509953d4c.html