原题来自: javascript-puzzlersjavascript
你们能够先去作一下感觉感觉. 当初个人成绩是 19/44...java
["1", "2", "3"].map(parseInt);
复制代码
首先, map
接受两个参数, 一个回调函数 callback
, 一个回调函数的this
值,其中回调函数接受三个参数 currentValue, index, array
;而题目中, map 只传入了回调函数--parseInt.其次, parseInt
只接受两个两个参数 string, radix(基数)
.正则表达式
- 在没有指定基数,或者基数为 0 的状况下,JavaScript 做以下处理:
- 若是字符串 string 以"0x"或者"0X"开头, 则基数是 16 (16 进制).
- 若是字符串 string 以"0"开头, 基数是 8(八进制)或者 10(十进制),那么具体是哪一个基数由实现环境决- 定。ECMAScript 5 规定使用 10,可是并非全部的浏览器都遵循这个规定。所以,永远都要明确给出
radix
参数的值。- 若是字符串 string 以其它任何值开头,则基数是 10 (十进制)。
parseInt('1', 0);
parseInt('2', 1);
parseInt('3', 2);
复制代码
因此答案是 [1, NaN, NaN]
chrome
[typeof null, null instanceof Object];
复制代码
typeof
返回一个表示类型的字符串。 instanceof
、instanceof
运算符用来检测 constructor.prototype
是否存在于参数 object
的原型链上。 由于 typeof null === 'object'
自语言之初就是这样....数组
typeof
的结果请看下表:浏览器
type // result
undefined // "undefined"
null // "object"
Boolean // "boolean"
Number // "number"
String // "string"
Symbol // "symbol"
Host object // Implementation-dependent
Function // "function"
Object // "object"
复制代码
因此答案 [object, false]
app
[[3, 2, 1].reduce(Math.pow), [].reduce(Math.pow)];
复制代码
arr.reduce(callback[, initialValue])
复制代码
reduce
接受两个参数, 一个回调, 一个初始值. 回调函数接受四个参数 previousValue
, currentValue
, currentIndex
, array
须要注意的是 若是数组为空且未提供初始值,则将引起类型错误。 因此第二个表达式会报异常. 第一个表达式等价于 Math.pow(3, 2) => 9; Math.pow(9, 1) =>9
函数
答案 an error
post
var val = "smtg";
console.log("Value is " + (val === "smtg") ? "Something" : "Nothing");
复制代码
简而言之 + 的优先级 大于 ?学习
因此原题等价于 'Value is true' ? 'Somthing' : 'Nonthing'
而不是 'Value is' + (true ? 'Something' : 'Nonthing')
答案 'Something'
var name = "World!";
(function() {
if (typeof name === "undefined") {
var name = "Jack";
console.log("Goodbye " + name);
} else {
console.log("Hello " + name);
}
})();
复制代码
javascript做用域中的变量提高。变量提高是 JavaScript 将声明移至做用域 scope (全局域或者当前函数做用域) 顶部的行为。
这题目至关于
var name = "World!";
(function() {
var name; // 如今的name是undefined
if (typeof name === "undefined") {
name = "Jack";
console.log("Goodbye " + name);
} else {
console.log("Hello " + name);
}
})();
复制代码
答案是 Goodbye Jack
var END = Math.pow(2, 53);
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) {
count++;
}
console.log(count);
复制代码
js 中能够表示的最大整数不是 2 的 53 次方,而是 1.7976931348623157e+308。 2 的 53 次方不是 js 能表示的最大整数而应该是能正确计算且不失精度的最大整数,能够参见 js 权威指南。 9007199254740992 +1 仍是 9007199254740992 ,这就是由于精度问题,若是 9007199254740992 +11 或者 9007199254740992 +111 的话,值是会发生改变的,只是这时候计算的结果不是正确的值,就是由于精度丢失的问题。
它进入无限循环
答案是 other
var ary = [0, 1, 2];
ary[10] = 10;
ary.filter(function(x) {
return x === undefined;
});
复制代码
答案是 []
咱们来看一下 Array.prototype.filter 的 polyfill:
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisArg*/) {
"use strict";
if (this === void 0 || this === null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function") {
throw new TypeError();
}
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
// 注意这里!!!
var val = t[i];
if (fun.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
return res;
};
}
复制代码
咱们看到在迭代这个数组的时候, 首先检查了这个索引值是否是数组的一个属性, 那么咱们测试一下.
0 in ary; => true
3 in ary; => false
10 in ary; => true
复制代码
也就是说 从 3 - 9 都是没有初始化的'坑'!, 这些索引并不存在与数组中. 在 array 的函数调用的时候是会跳过这些'坑'的.
var two = 0.2;
var one = 0.1;
var eight = 0.8;
var six = (0.6)[(two - one == one, eight - six == two)];
复制代码
IEEE 754 标准中的浮点数并不能精确地表达小数
那何时精准, 何时不经准呢? 笔者也不知道...
答案 [true, false]
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"));
// switch 是严格比较, String 实例和 字符串不同.
var s_prim = "foo";
var s_obj = new String(s_prim);
console.log(typeof s_prim); // "string"
console.log(typeof s_obj); // "object"
console.log(s_prim === s_obj); // false
复制代码
字符串字面量和直接调用String()方法(不使用new调用构造函数)的结果是原始字符串。JS自动回转化原始字符串到String对象。因此能够在原始字符串上使用用String对象的方法。而在上下文中,在原始字符串的方法被调用或者从其中获取属性时,JS会自动包裹原始字符串而后调用方法或者获取属性。
答案是 Do not know!
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"));
复制代码
String(x) does not create an object but does return a string, i.e. typeof String(1) === "string"
仍是刚才的知识点, 只不过 String 不只是个构造函数 直接调用返回一个字符串哦.
答案 Case A
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);
复制代码
7 % 2 => 1
4 % 2 => 0
'13' % 2 => 1
-9 % % 2 => -1
Infinity % 2 => NaN
复制代码
须要注意的是 余数的正负号随第一个操做数.
答案 [true, true, true, false, false]
parseInt(3, 8);
parseInt(3, 2);
parseInt(3, 0);
复制代码
第一个值为3没什么好说的。若是出现的数字不符合后面输入的进制,则为NaN,因此第二个值为NaN。而radix为0时的状况第一题下面有介绍,这里也是同样为默认10
答案 3, NaN, 3
Array.isArray(Array.prototype);
复制代码
一个不为人知的实事: Array.prototype => [];
答案: true
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log("wut");
}
复制代码
解析:
而==左右的转换,会使用若是一个操做值为布尔值,则在比较以前先将其转换为数值的规则来转换,Number([0]),也就是0,因而变成了0 == true,结果天然是false,因此最终结果为B
答案:false
[] == [];
复制代码
[] 是Object
, 两个 Object
不相等
当==运算符当左右都是对象时,则会比较其是否指向同一个对象。而每次调用字面量建立,都会创造新的对象,也就是会开辟新的内存区域。因此指针的值天然不同
答案是 false
"5" + 3;
"5" - 3;
复制代码
+
用来表示两个数的和或者字符串拼接, -
表示两数之差.
-
会尽量的将两个操做数变成数字, 而 +
若是两边不都是数字, 那么就是字符串拼接.
答案是 '53', 2
var arr = Array(3);
arr[0] = 2;
arr.map(function(elem) {
return "1";
});
复制代码
稀疏数组. 同第 7 题.
题目中的数组实际上是一个长度为3
, 可是没有内容的数组, array
上的操做会跳过这些未初始化的'坑'.
因此答案是 ["1", undefined × 2]
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
复制代码
对象键自动转换为字符串。咱们试图将一个对象设置为对象 a 的键,其值为123。
可是,当对象自动转换为字符串化时,它变成了[Object object]
。因此咱们在这里说的a["Object object"] = 123
是。而后,咱们能够尝试再次作一样的事情。 c 对象一样会发生隐式类型转换。那么,a["Object object"] = 456
。
而后,咱们打印a[b]
,它其实是a["Object object"]
。咱们将其设置为456
,所以返回456
。
答案: 456
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a, b, c) {
c = 10;
sidEffecting(arguments);
return a + b + c;
}
bar(1, 1, 1);
复制代码
这是一个大坑, 尤为是涉及到 ES6 语法的时候
在调用函数时,函数内部的arguments维护着传递到这个函数的参数列表。它看起来是一个数组,但实际上它只是一个有length属性的Object,不从Array.prototype
继承。因此没法使用一些Array.prototype
的方法。
arguments对象其内部属性以及函数形参建立getter和setter方法,所以改变形参的值会影响到arguments对象的值,反过来也是同样
也就是说 arguments
是一个 object
, c 就是 arguments[2]
, 因此对于 c 的修改就是对 arguments[2]
的修改.
因此答案是 21.
然而!!!!!!
当函数参数涉及到 any rest parameters, any default parameters or any destructured parameters
的时候, 这个 arguments
就不在是一个 mapped arguments object
了.....
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a, b, c = 3) {
c = 10;
sidEffecting(arguments);
return a + b + c;
}
bar(1, 1, 1);
复制代码
答案是: 12
!!!!
var a = 111111111111111110000,
b = 1111;
a + b;
复制代码
JavaScript 数字的题,与第七题考察点类似。因为 JavaScript 实际上只有一种数字形式 IEEE 754 标准的 64 位双精度浮点数,其所能表示的整数范围为-2^53~2^53
(包括边界值)。这里的 111111111111111110000 已经超过了2^53 次方,因此会发生精度丢失的状况。
答案仍是 111111111111111110000
var x = [].reverse;
x();
复制代码
这题考查的是函数调用时的 this 和 Array.prototype.reverse 方法。
The reverse method transposes the elements of the calling array object in place, mutating the array, and returning a reference to the array.
也就是说 最后会返回这个调用者(this), 但是 x 执行的时候是上下文是全局. 那么最后返回的是 window. 关于 this 指向问题
答案是 window
Number.MIN_VALUE > 0;
复制代码
MIN_VALUE
属性是 JavaScript 中可表示的最小的数(接近 0 ,但不是负数),它的近似值为 5 x 10-324。
有兴趣的话能够看一下这个MDN
答案是 true
列举 Number 的其它常量:
[1 < 2 < 3, 3 < 2 < 1];
复制代码
运算符的运算顺序和隐式类型转换的题,从MDN 上运算符优先级,'<'运算符顺序是从左到右,因此变成了[true < 3, false < 1]
3 > 2 && 2 > 1;
// returns true
3 > 2 > 1;
// returns false because 3 > 2 is true, and true > 1 is false
// Adding parentheses makes things clear: (3 > 2) > 1
复制代码
这个题等价于
1 < 2 => true;
true < 3 => 1 < 3 => true;
3 < 2 => false;
false < 1 => 0 < 1 => true;
复制代码
因此,这里首先经过**Number()**转换为数字而后进行比较,true 会转换成 1,而 false 转换成 0,就变成了[1 < 3, 0 < 1]
参考
答案是 [true, true]
// the most classic wtf
2 == [[[2]]];
复制代码
又是隐式类型转换的题,
也就是说左右两边都被转换成了字符串,而字符串都是"2"
这里首先须要对==右边的数组进行类型转换,根据如下规则(来自justjavac 的文章《「译」JavaScript 的怪癖 1:隐式类型转换》):
>3 * { valueOf: function () { return 5 } }
// 15
// 第三步示例:
>function returnObject() { return {} }
>3 * { valueOf: returnObject, toString: returnObject }
`TypeError: Cannot convert object to primitive value`
复制代码
若是把对象转换成字符串时,则转换操做的第一步和第二步的顺序会调换: 先尝试 toString() 进行转换,若是不是原始值,则再尝试使用 valueOf()。
因此右侧被使用 toString()方法转换为"2"
而后又经过 Number("2")转换为数字 2 进行比较,结果就是 true 了
答案是 true
3.toString()
3..toString()
3...toString()
复制代码
JavaScript 会在调用方法时对原始值进行包装,但在于这个点是小数点、仍是方法调用的点,因而乎第一个就是error
了,由于 JavaScript 解释器会将其第一个点认为是小数点。
第二个则很好说通了,第一个点解释为小数点,变成了(3.0).toString(),结果就是"3"
了
第三个也是,第一个点为小数点,第二个是方法调用的点,可是后面接的不是一个合法的方法名,因而乎就error
了
若是
var a = 3;
a.toString(); // "3"
复制代码
这是由于在 js 中 1.1
, 1.
, `.`` 都是合法的数字. 那么在解析 3.toString 的时候这个** . **究竟是属于这个数字仍是函数调用呢? 只能是数字, 由于 3.合法啊!
答案是 error, '3', error
(function() {
var x = (y = 1);
})();
console.log(y);
console.log(x);
复制代码
变量提高和隐式定义全局变量的题,也是一个 JavaScript 经典的坑...
y 被赋值到全局. x 是局部变量. 因此打印 x 的时候会报 ReferenceError: x is not defined
答案是 1, error
var a = /123/,
b = /123/;
a == b;
a === b;
复制代码
JavaScript 中的正则表达式依旧是对象,==运算符左右两边都是对象时,会比较他们是否指向同一个对象.
答案 false, false
var a = [1, 2, 3],
b = [1, 2, 3],
c = [1, 2, 4];
a == b;
a === b;
a > c;
a < c;
复制代码
JavaScript 中 Array 的本质也是,因此前两个的结果都是 false,
而 JavaScript 中 Array 的'>'运算符和'<'运算符的比较方式相似于字符串比较字典序
会从第一个元素开始进行比较,若是同样比较第二个,还同样就比较第三个,如此类推,因此第三个结果为 false,第四个为 true。
答案 false, false, false, true
var a = {},
b = Object.prototype;
[a.prototype === b, Object.getPrototypeOf(a) === b];
复制代码
原型链的题(总会有的),考查的__proto__
和prototype
的区别。首先要明确对象和构造函数的关系,对象在建立的时候,其__proto__
会指向其构造函数的prototype
属性
实例对象是没有prototype
属性的,只有函数才有,因此a.prototype
实际上是undefined
,第一个结果为 false
Object
其实是一个构造函数(typeof Object的结果为"function"
),使用字面量建立对象和new Object
建立对象是同样的,因此a.__proto__
也就是Object.prototype
,而Object.getPrototypeOf(a)与a.__proto__
是同样的,因此第二个结果为true
答案 [false, true]
function f() {}
var a = f.prototype,
b = Object.getPrototypeOf(f);
a === b;
复制代码
f.prototype 是使用使用 new 建立的 f 实例的原型
而 Object.getPrototypeOf 是 f 函数的原型.
a === Object.getPrototypeOf(new f()) // true
b === Function.prototype // true
复制代码
答案 false
function foo() {}
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name];
复制代码
考察了函数的 name 属性,使用函数定义方式时,会给 function 对象自己添加一个 name 属性,保存了函数的名称,很好理解oldName为"foo"
。name 属性时只读的,不容许修改,因此foo.name = "bar"
;以后,foo.name仍是"foo"
,
答案 ['foo', 'foo']
"1 2 3".replace(/\d/g, parseInt);
复制代码
String.prototype.replace
、正则表达式的全局匹配和 parseInt,
首先须要肯定 replace 会传给 parseInt 哪些参数。举个栗子:
"1 2 3".replace(/\d/g, function() {
console.log(arguments);
});
//输出结果:
//["1", 0, "1 2 3"]
//["2", 2, "1 2 3"]
//["3", 4, "1 2 3"]
复制代码
一共三个:
这样就很好理解了,又回到以前 parseInt 的问题了,结果就是 parseInt("1", 10), parseInt("2", 2), parseInt("3", 4)
答案: 1, NaN, 3
function f() {}
var parent = Object.getPrototypeOf(f);
f.name; // ?
parent.name; // ?
typeof eval(f.name); // ?
typeof eval(parent.name); // ?
复制代码
第一 f.name 值为"f"
,第三 eval("f")则会输出 f 函数,因此结果为"function"
第二在本身的浏览器测试的时候是 ''
, 第四是 'undefined'
var lowerCaseOnly = /^[a-z]+$/;
[lowerCaseOnly.test(null), lowerCaseOnly.test()];
复制代码
正则表达式的**test()**会自动将参数转换为字符串,原式就变成了[lowerCaseOnly.test("null"), lowerCaseOnly.test("undefined")]
答案:[true, true]
[, , ,].join(", ");
复制代码
[,,,] => [empty × 3]
复制代码
JavaScript 中使用字面量建立数组时,若是最末尾有一个逗号',',会背省略,因此这是个长度为三的稀疏数组(这是长度为三, 并无 0, 1, 2 三个属性哦)(都是 undefined);
答案: ", , "
var a = { class: "Animal", name: "Fido" };
a.class;
复制代码
经典坑中的一个,class 是关键字。根据浏览器的不一样,结果不一样:
chrome 的结果: "Animal"
Firefox 的结果:"Animal"
Opera 的结果:"Animal"
IE 8 以上也是: "Animal"
IE 8 及如下: 报错
因此答案不重要, 重要的是本身在取属性名称的时候尽可能避免保留字. 若是使用的话请加引号 a['class']
var a = new Date("epoch");
复制代码
简单来讲, 若是调用 Date 的构造函数传入一个字符串的话须要符合规范, 即知足 Date.parse
的条件.
另外须要注意的是 若是格式错误 构造函数返回的还是一个 Date 的实例 Invalid Date
.
答案 Invalid Date
var a = Function.length,
b = new Function().length;
a === b;
复制代码
咱们知道一个function(Function 的实例)
的 length 属性就是函数签名的参数个数, 因此 b.length == 0
.
另外 Function.length
定义为 1......
因此不相等......
答案 false
var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c];
复制代码
答案 [false, false, false]
var min = Math.min(),
max = Math.max();
min < max;
复制代码
Math.min
的参数是 0 个或者多个。若是是多个参数很容易理解,返回参数中最小的。
若是没有参数,则返回Infinity
。Infinity
是 javascript 中全局对象的一个属性,在浏览器环境中就是 window
对象的一个属性,表示无穷大。
而 Math.max()
没有传递参数时返回的是 -Infinity
。
所以 Math.min()
要比 Math.max()
大。
答案 false
function captureOne(re, str) {
var match = re.exec(str);
return match && match[1];
}
var numRe = /num=(\d+)/gi,
wordRe = /word=(\w+)/i,
a1 = captureOne(numRe, "num=1"),
a2 = captureOne(wordRe, "word=1"),
a3 = captureOne(numRe, "NUM=2"),
a4 = captureOne(wordRe, "WORD=2");
[a1 === a2, a3 === a4];
复制代码
由于第一个正则有一个 g 选项 它会‘记忆’他所匹配的内容, 等匹配后他会从上次匹配的索引继续, 而第二个正则不会
因此 a1 = '1'; a2 = '1'; a3 = null; a4 = '2'
答案: [true, false]
var a = new Date("2014-03-19"),
b = new Date(2014, 03, 19);
[a.getDay() === b.getDay(), a.getMonth() === b.getMonth()];
a.getDay(); // 3
b.getDay(); // 6
a.getMonth(); // 2
b.getMonth(); // 3
复制代码
new Date("2014-03-19")
若是传入的是一个符合规则的日期字符串("2014-03-19"),获得的就是对应的标准时间对象 // Wed Mar 19 2014 08:00:00 GMT+0800 (中国标准时间)
new Date(2014, 03, 19)
若是传入的是三个,第三个识别为日期// Wed Mar 19 2014 08:00:00 GMT+0800 (中国标准时间)
答案:[false, false]
if ("http://giftwrapped.com/picture.jpg".match(".gif")) {
("a gif file");
} else {
("not a gif file");
}
复制代码
tring.prototype.match
接受一个正则, 若是不是, 按照 new RegExp(obj)
转化. 因此 . 并不会转义 那么 /gif 就匹配了 /.gif/
答案: 'a gif file'
function foo(a) {
var a;
return a;
}
function bar(a) {
var a = "bye";
return a;
}
[foo("hello"), bar("hello")];
复制代码
在两个函数里, a做为参数其实已经声明了, 因此 var a; var a = 'bye'
其实就是 a; a ='bye'
答案: ["hello", "bye"]
我只是一个分享者,代码的搬运工、一个追求者、一个学习者,有不一样的意见或新的想法,提出来,咱们一块儿研究。
鲁迅曾经说过**知识遍地,拾到了就是你的
**。
相似文章: 悦老板