原題來自: 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"]
我只是一個分享者,代碼的搬運工、一個追求者、一個學習者,有不一樣的意見或新的想法,提出來,咱們一塊兒研究。
魯迅曾經說過**知識遍地,拾到了就是你的
**。
相似文章: 悅老闆