❝漫漫編程路,總有一些坑讓你淚流滿面。前端
❞
不寫回調函數的話,是按照什麼排序呢?git
JavaScript默認使用字典序(alphanumeric)來排序。所以結果是[1,10,2,5]github
正確排序的話,應該[1,2,5,10].sort( (a,b) => a-b )web
你認爲輸出是什麼?面試
上面的表達式至關於'b'+'a'+ (+'a')+'a',由於(+'a')是NaN,因此:編程
'b'+'a'+ (+'a')+'a' = 'b'+'a'+ "NaN"+'a'='baNaNa'數組
這是一個經典JavaScript面試題瀏覽器
let res = new Array()
for(var i = 0; i < 10; i++){ res.push(function(){ return console.log(i) }) } res[0]() res[1]() res[2]() 複製代碼
指望輸出的是0,1,2,實際上卻不會。緣由就是涉及「做用域」,怎麼解決呢?安全
res.push(console.log.bind(null, i))
複製代碼
解法還有其餘的,好比使用IIFE,造成私有做用域等等作法。閉包
function fun(n,o) {
console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,? 複製代碼
「留給大家思考」
var a = [0];
if (a) { console.log(a == true); } else { console.log("wut"); } 複製代碼
大家以爲答案是多少呢?這題涉及到隱式轉換了,這個坑我本身的好好補一補
// 答案:false
「再來一道?」
function fn() {
return 20; } console.log(fn + 10); // 輸出結果是多少 複製代碼
function fn() {
return 20; } fn.toString = function() { return 10; } console.log(fn + 10); // 輸出結果是多少? 複製代碼
function fn() {
return 20; } fn.toString = function() { return 10; } fn.valueOf = function() { return 5; } console.log(fn + 10); // 輸出結果是多少? 複製代碼
「說到底JS類型轉換的好好補一補了」
[1<2<3,3<2<1]
//[false,false] //[true,true] //[false,true] //[true,false] 複製代碼
選一個吧,比較操做符,賦值運算符優先級哪一個更高呢?
面試的時候,問你這個問題,要是回答錯誤的話,估計面試官對基礎非常懷疑!!!
問你這個題目的時候,你能夠牽扯出不少問題,好比JS如何存儲小數的呢?好比聊一聊二進制,好比實際開發中,遇到精度的問題,你是怎麼解決的,你有什麼好辦法。
聊完這個,你能夠牽扯出最大安全數,好比JavaScript的最大安全整數是多少,超出這個範圍的話,怎麼解決精度問題呢?
ES規範中新提出的BigInt解決了什麼問題呢,你又發現了BigInt中哪些坑呢?
如何解決精度問題呢?
這裏推薦Number-Precision庫,不到1K的體積。
function sidEffecting(ary) {
ary[0] = ary[2]; } function bar(a, b, c) { c = 10 sidEffecting(arguments); return a + b + c; } function demo (arg) { arg.name = 'new Name' } console.log(bar(2, 2, 2)) 複製代碼
涉及到ES6語法,這題答案確定都會作是22,可是呢,稍微改變一下題目,就比較坑了….
function sidEffecting(ary) {
ary[0] = ary[2]; } function bar(a, b, c = 4) { c = 10 sidEffecting(arguments); return a + b + c; } function demo (arg) { arg.name = 'new Name' } console.log(bar(2, 2, 2)) 複製代碼
這個答案是多少呢?根據MDN上對argument有更加準確的定義,看argument
❝當非嚴格模式中的函數「有」包含剩餘參數、默認參數和解構賦值,那麼
❞arguments
對象中的值「不會」跟蹤參數的值(反之亦然)。
找到這句話,bar函數存在默認參數,而且在非嚴格模式下,因此不會跟蹤參數的值,天然結果就14
「請讀者細細體會」
let demo1 = {class: "Animal", name: 'sheet'};
console.log(demo1.class) 複製代碼
比較流氓,這個跟瀏覽器相關,class是保留字(如今的話,class是關鍵字),答案並沒關係,重要的是本身在取屬性名稱的時候儘可能避免保留字. 若是使用的話請加引號 a['class']。
「保留字vs關鍵字」
我的理解的話,關鍵字就是有特殊含義的,不用用做變量名。好比
let class = 123;
複製代碼
如今看來確定報錯,那有什麼須要咱們注意的呢?
let undefined = 123;
複製代碼
這樣子並不會報錯,這個跟瀏覽器有點關係,這樣子看來undefined不是關鍵字。因此爲了保險起見,「建議你們在判斷一個變量是否是未定義的話,儘可能使用void 0 === undefined」 頗有可能undefined會被看成是變量來賦值
「void 0 值就是undefined」
這個應該是常常碰見的題了,搞明白很簡單,map函數怎麼使用,parseInt函數怎麼使用
關於Array數組的話,我以前寫了一篇文章,從「源碼角度解析大部分方法」
點進去重溫一遍:[乾貨👍]從詳細操做js數組到淺析v8中array.js
map接受兩個參數,一個callback,一個this,即調用函數時this指向,其中callback回調函數是三個參數,一個currentValue,index,array;
parseInt接受兩個參數:string,radix(基數)
返回NaN有兩種狀況
radix
小於
2
或大於
36
,或
parseInt('1', 0);
parseInt('2', 1); parseInt('3', 2); 複製代碼
二者結合的話,結果天然很明顯,[1,NaN,NaN]
Math.min() < Math.max() // false
複製代碼
按照常規思路的話,應該是true,畢竟最小值應該小於最大值,可是實際狀況是false
緣由:
要是面試官問這個問題,額。。。。
輸出是什麼?注意不是[].concat([1,2,3])
// [1,2,3] // Uncaught SyntaxError: .... // undefined 複製代碼
答案是undefined,緣由是什麼呢?
第一步計算[].concat,結果是Array.prototype.concat
第二步執行一個逗號操做符,逗號操做符對它的每一個操做對象求值(從左至右),而後返回最後一個操做對象的值。
>1,2,3 返回3 複製代碼
第三步執行一個數組訪問運算或屬性訪問運算
因此上面[].concat[1,2,3] 等價於Array.prototype.concat[3]
那麼結果天然就是 undefined
。
//2 or -1
怎麼辦呢?
let realIsNaN = value => typeof value === 'number' && isNaN(value);
複製代碼
先要判斷類型,是由於字符串轉換會先轉換成數字,轉換失敗爲 NaN。因此和 NaN 相等。
isNaN('jjjj') —> true
複製代碼
第二種方法
let realIsNaN = value => value !== value;
複製代碼
Number.isFinite('0') === isFinite('0')
Number.isFinite(0) === isFinite('0') 複製代碼
打印結果是什麼,能不能具體說一說?
❝Number.isFinite()檢測有窮性的值,惟一和全局isFinite()函數相比,這個方法不會強制將一個非數值的參數轉換成數值,這就意味着,只有數值類型的值,且是有窮的(finite),才返回
❞true
。
天然答案就是 false,true
function Foo() {
getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //請寫出如下輸出結果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName(); 複製代碼
let newList = [1,2,3].push(4)
console.log(newList.push(4)) 複製代碼
認爲輸出什麼?
// Error
緣由在於Array.prototype.pu sh()返回的是新數組的長度,因此呢4.push(5)天然Error
function foo1() { return { bar: "hello" }; } function foo2() { return { bar: "hello" }; } var a=foo1(); var b=foo2(); console.log(a) //Object {bar: "hello"} console.log(b) //underfind //仔細看就知道了 // 會在第10行加入一個`;` 複製代碼
會在第10行自動加一個分號; 因此返回的就是undefined
function foo() {
let a = b = 0; a++; return a; } foo(); typeof a; // => ??? typeof b; // => ??? 複製代碼
上面的let a = b = 0; 等價於 window.b = 0, let a = b;
const length = 4;
const numbers = []; for (var i = 0; i < length; i++);{ numbers.push(i + 1); } numbers; // => ??? 複製代碼
惟一須要注意的就是for語句
後面帶了;
沙雕題
加了;
,會認爲for執行完,因此指定的都是空語句,最後numbers爲[5]
console.log('Hello World'[4])
複製代碼
使用的就是方括號表示法獲取字符串特定索引的字符,值得注意的是,IE7低版本使用的是charAt()
因此這題輸出o
const name = 'TianTianUp'
console.log(!typeof name === 'string') console.log(!typeof name === 'object') 複製代碼
typeof name 返回的是 ’string‘, 字符串’string‘是一個truthy值。所以!typeof name 返回一個布爾值false。因此
false === ’string'
和 false === ’object‘返回false
(檢測一個類型的值話,咱們應該使用 !==而不是!typeof)
const nums = [1, 2, 3, 4, 5, 6];
let firstEven; nums.forEach(n => { if (n % 2 ===0 ) { firstEven = n; return n; } }); console.log(firstEven); 複製代碼
惟一須要注意的就是forEach源碼是怎麼寫的,看過源碼的都知道,forEach使用return是不能停止循環的,或者說每一次調用callback函數,終止的是當前的一次,而不是整個循環。
結果天然就是6
有不錯的題目,或者是JS中容易出錯的坑,掘金網友能夠提出來❤️,我會更新的啦🆗
若是你以爲這篇內容對你挺有有幫助的話:
點贊支持下吧,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
歡迎在留言區與我分享你的想法,也歡迎你在留言區記錄你的思考過程。
以爲不錯的話,也能夠看看往期文章:
[誠意滿滿👍]Chrome DevTools調試小技巧,效率➡️🚀🚀🚀
[1.1W字]寫給女朋友的祕籍-瀏覽器工做原理(渲染流程)篇