第一題:['1', '2', '3'].map(parseInt) what & why ?
答案:[1, NaN, NaN]
// map參數(shù)使用
arr.map(function(currentValue, index, arr) {})
// 第一參數(shù)為當前被處理的元素,第二參數(shù)為該元素索引
// 而parseInt也是一個函數(shù),解析字符串為指定基數(shù)
parseInt(string, radix);
// 第一參數(shù)為被處理的字符串,第二參數(shù)為解析的基數(shù)
當 radix 為 0 時,按照基數(shù)為10處理, 返回 1;
當 radix 為 1 時,parseInt 基數(shù)范圍是 2 ~ 36,無法解析, 返回 NaN;
當 radix 為 2 時,二進制只能存在0 和 1,最后返回 NaN。
第二題:將數(shù)組扁平化并去除其中重復數(shù)據(jù),最終得到一個升序且不重復的數(shù)組
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
Array.from(new Set(arr.flat(Infinity))).sort((a, b) => {return a - b});
第三題:請把兩個數(shù)組 [‘A1’, ‘A2’, ‘B1’, ‘B2’, ‘C1’, ‘C2’, ‘D1’, ‘D2’] 和 [‘A’, ‘B’, ‘C’, ‘D’],合并為 [‘A1’, ‘A2’, ‘A’, ‘B1’, ‘B2’, ‘B’, ‘C1’, ‘C2’, ‘C’, ‘D1’, ‘D2’, ‘D’]。
let arr1 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'];
let arr2 = ['A', 'B', 'C', 'D'].map(item => item + 3);
let arr3 = [...arr1, ...arr2].sort().map(item => {
if (item.includes('3')) {
return item.split('')[0];
}
return item;
})
第四題:改造下面的代碼,使之輸出0 - 9。
for (var i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}
// 解法一:ES6 let
for (let i = 0; i < 10; i ++) {
setTimeout(() => {
console.log(i);
}, 1000)
}
// 解法二: 自執(zhí)行函數(shù)
for (let i = 0; i < 10; i ++) {
(function(i) {
setTimeout(() => {
console.log(i);
}, 1000)
})(i);
}
// 解法三:setTimeout 第三參數(shù),作為 callback 的參數(shù)
for (var i = 0; i < 10; i ++) {
setTimeout((i) => {
console.log(i);
}, 1000, i)
}
第五題:以下代碼打印的是什么?為什么?
var a = 10;
(function a() {
a = 20;
console.log(a);
console.log(window.a);
})();
console.log(a);
打印結果為: 函數(shù)a 10 10
因為是自執(zhí)行函數(shù),產(chǎn)生了自己的作用域,所有不會修改全局 window 下的變量 a。
而自執(zhí)行函數(shù)中對自身進行賦值是無效的代碼, 所以 a = 20 并未生效,但在自執(zhí)行函數(shù)中可以定義與之同名的作用域變量 (看第六題)。
第六題:簡單改造以下代碼,使之打印10 或 20
var b = 10;
(function b(){
b = 20;
console.log(b);
})();
// 打印 10
var b = 10;
(function b() {
b = 20;
console.log(window.b);
})();
// 打印20
var b = 10;
(function b() {
var b = 20;
console.log(b);
})();
第七題:實現(xiàn)一個 sleep 函數(shù),比如 sleep(1000) 意味著等待1000毫秒,可從 Promise、Generator、Async/Await 等角度實現(xiàn)。
// Promise實現(xiàn):
const sleep = (time) => {
return new Promise(resolve => setTimeout(resolve, time))
}
sleep(1000).then(() => {
console.log("1秒后調(diào)用then方法");
})
// async實現(xiàn):
const sleep = (time) => {
return new Promise(resolve => setTimeout(resolve, time))
}
async function asyncFun() {
console.log("發(fā)生在sleep函數(shù)之前");
await sleep(1000).then(() => console.log("執(zhí)行sleep函數(shù)"));
console.log("發(fā)生在sleep函數(shù)之后");
}
asyncFun();
// Generator實現(xiàn):
function* sleepGenerator(time) {
yield new Promise((resolve) => {
setTimeout(resolve, time);
})
}
sleepGenerator(1000).next().value.then(() => console.log("1秒后執(zhí)行then方法"));
第八題:以下代碼執(zhí)行結果并解釋為什么
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)
打印結果:[ , , 1, 2, splice: ?, push: ?]。
首先這個對象的key是字符串的數(shù)字,并且存在length屬性,是一個類數(shù)組,所以key表示類數(shù)組的下標。當調(diào)用數(shù)組的push方法時,會向類數(shù)組末尾添加元素,由于length定義為2,所以會在第二個元素后面添加,對應的下標為2,所以 push(1) 替換了 下標為 2 的值(3),最后 length 會取決于最初定義的length和對類數(shù)組的操作,length最初為2,添加了兩個元素后length變?yōu)?4。
第九題:實現(xiàn) (5).add(3).minus(2) 功能。
Number.prototype.add = function(num) {
return this + num;
}
Number.prototype.minus = function(num) {
return this - num;
}
let number = (5).add(3).minus(2);
第十題:輸出以下代碼的執(zhí)行結果并解釋為什么
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x)
console.log(b.x)
執(zhí)行結果是: a.x = undefined,b.x = {n: 2}
關鍵點在于:
1、優(yōu)先級: . (點) 的優(yōu)先級高于 = ,所以先執(zhí)行和 a.x,堆內(nèi)存中的 {n: 1} 就會變成 {n: 1, x: undefined},相應的 b 也發(fā)生改變,因為指向同一對象。
2、賦值操作是從右到左:所以先執(zhí)行a = {n: 2},此時a的引用就被改變了,然后返回值又賦值給了a.x, 需要注意這里的 a.x 是第一步中的 {n: 1, x: undefined} 那個對象, 其實就是對象 b,相當于訪問了 b.x = {n: 2}。
第十一題:某公司 1 到 12 月份的銷售額存在一個對象里面,如下:{1:222, 2:123, 5:888},請把數(shù)據(jù)處理為如下結構:[222, 123, null, null, 888, null, null, null, null, null, null, null]。
let info = {1: 222, 2: 123, 5: 888};
// 方式一:
let arr = new Array(12).fill(null); // 創(chuàng)建一個長度為10并且每個元素都為null的數(shù)組
Object.keys(info).forEach(key => {
arr[key - 1] = info[key];
})
console.log(arr);
// 方式二:
const result = Array.from({length: 12}).map((_, index) => info[index + 1] || null); // 將length為12的類數(shù)組轉(zhuǎn)為數(shù)組,通過map映射。
console.log(result);
十二題:給定兩個數(shù)組,寫一個方法來計算它們的交集。
function union(arr1, arr2) {
return arr1.filter(item =>{
return arr2.indexOf(item) > - 1;
})
}
const arr1 = [1,2,2,1];
const arr2 = [2,3,2];
console.log(union(arr1, arr2)); // [2, 2]
十三題:隨機生成一個長度為 10 的整數(shù)類型的數(shù)組,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],將其排列成一個新數(shù)組,要求新數(shù)組形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]。
let arr = [];
for (var i = 0; i < 10; i ++) {
arr.push(Math.floor(Math.random() * 100));
}
function formArray(arr) {
const sortedArr = Array.from(new Set(arr)).sort((a, b) => a - b); // 先進行去重、排序
const map = new Map(); // 利用map進行存儲
sortedArr.forEach((item) => {
const key = Math.floor(item / 10);
const group = map.get(key) || [];
group.push(item);
map.set(key, group);
});
return [...map.values()];
}
let value = formArray(arr);
十四題:如何把一個字符串的大小寫取反(大寫變小寫小寫變大寫),例如 ’AbC’ 變成 ‘a(chǎn)Bc’ 。
function processString (str) {
var arr = str.split('');
var new_arr = arr.map((item) => {
return item === item.toUpperCase() ? item.toLowerCase() : item.toUpperCase();
});
return new_arr.join('');
}
十五題:實現(xiàn)一個字符串匹配算法,從長度為 n 的字符串 S 中,查找是否存在字符串 T,T 的長度是 m,若存在返回所在位置。
const find = (S, T) => {
if (S.length < T.length) return -1
for (let i = 0; i < S.length; i++) {
if (S.slice(i, i + T.length) === T) return i
}
return -1
}
十六題:輸出以下代碼運行結果:
// example 1
var a={}, b='123', c=123;
a[b]='b';
a[c]='c';
console.log(a[b]);
// example 2
var a={}, b=Symbol('123'), c=Symbol('123');
a[b]='b';
a[c]='c';
console.log(a[b]);
// example 3
var a={}, b={key:'123'}, c={key:'456'};
a[b]='b';
a[c]='c';
console.log(a[b]);
這道題主要考察對象的鍵名的轉(zhuǎn)換:
- 對象的鍵名只能是字符串和 Symbol 類型。
- 其他類型的鍵名會被轉(zhuǎn)為字符串。
- 在將對象轉(zhuǎn)字符串時默認調(diào)用 toString 方法
// example 1
var a={}, b='123', c=123;
a[b]='b';
a[c]='c'; // c 的鍵名會被轉(zhuǎn)為字符串 '123',這里會把b覆蓋掉
console.log(a[b]); // 輸出 c
// example 2
var a={}, b=Symbol('123'), c=Symbol('123');
a[b]='b'; // b 是 Symbol 類型, 不需要轉(zhuǎn)換
a[c]='c'; // c 是 Symbol 類型, 不需要轉(zhuǎn)換,Symbol 表示唯一性,任何一個 Symbol值都是不等的,所以不會覆蓋 b
console.log(a[b]); // 輸出 b
// example 3
var a={}, b={key:'123'}, c={key:'456'};
a[b]='b'; // 對象類型轉(zhuǎn)字符串時會調(diào)用toString方法轉(zhuǎn)換成字符串 [object Object]
a[c]='c'; // 對象類型轉(zhuǎn)字符串時會調(diào)用toString方法轉(zhuǎn)換成字符串 [object Object]
console.log(a[b]); // 輸出 c
十七題:打印出 1 - 10000 之間的所有對稱數(shù) 例如:121、1331 等
[...Array(10000).keys()].filter((x) => {
return x.toString().length > 1 && x === Number(x.toString().split('').reverse().join(''))
})
十八題:算法題「移動零」,給定一個數(shù)組 nums,編寫一個函數(shù)將所有 0 移動到數(shù)組的末尾,同時保持非零元素的相對順序
function zeroMove(array) {
let len = array.length;
let j = 0; // 控制末尾第一個0的起始位置,防止死循環(huán)
for(let i=0;i<len-j;i++){
if(array[i]===0){
array.push(0);
array.splice(i,1);
i --;
j ++;
}
}
return array;
}
十九題:請實現(xiàn)一個 add 函數(shù),滿足以下功能。
add(1); // 1
add(1)(2); // 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
function add(){
var _args = [].slice.apply(arguments);
var _adder = function (){
_args.push(...arguments);
return _adder; // 每次都返回這個函數(shù),并利用閉包拿到 _args
}
_adder.valueOf = function(){
return _args.reduce(function(a,b)
return a+b;
})
}
return _adder;
}
console.log(+add(1)(2)(3));
二十題:給定一個整數(shù)數(shù)組和一個目標值,找出數(shù)組中和為目標值的兩個數(shù)。
示例:
給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
function anwser (arr, target) {
let map = {}
for (let i = 0; i < arr.length; i++) {
map[arr[i]] = i
}
for (let i = 0; i < arr.length; i++) {
var d = target - arr[i]
if (map[d]) {
return [i, map[d]]
}
}
return new Error('404 not found')
}
二十一:在輸入框中如何判斷輸入的是一個正確的網(wǎng)址。
const isUrl = urlStr => {
try {
const { href, origin, host, hostname, pathname } = new URL(urlStr)
return href && origin && host && hostname && pathname && true
} catch (e) {
return false
}
}
二十二:(京東)請寫出如下代碼的打印結果:
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
執(zhí)行結果: 4 2 1
解題:
function Foo() { // 1、首先這里定義了Foo方法,但沒有調(diào)用,所以沒有執(zhí)行內(nèi)部代碼
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a(); // 這里使用了Foo,但也沒有通過 () 調(diào)用,并且使用Foo.a不會在原型上查找。 這里打印 4
let obj = new Foo(); // 通過new 調(diào)用 Foo 返回一個對象,只有對象才可以訪問 this 和 原型prototype,并且對象訪問a方法時,不會去查找 Foo.a 定義的a方法
obj.a(); // 原型上有a方法,但函數(shù)體內(nèi)也有a方法,這里打印 2
Foo.a(); // 由于之前 通過new 調(diào)用了一次, 執(zhí)行了函數(shù)體內(nèi)的 Foo.a,這里打印 1
第二十三題: 求c的結果
var a = function() {
this.b = 1;
}
var b = function() {
var b = new a().b;
return 5 + b;
}
var c = b();
答案是 6。在 b 函數(shù)內(nèi)部定義了變量 b,當 new a().b 時,會先執(zhí)行new a(),并返回結果對象 {b: 1},再訪問 .b 得到 1。
第二十四題:
a = 1;
b = 2;
c = 2;
while(a < b < c) {
t = a;
a = b;
b = t;
c --;
}
console.log('' + a + b + c);
答案: 120。
解題:第一次進入 while 時,a < b 成立并返回 true,當 < c 時,< 會進行隱式轉(zhuǎn)換,將 true 轉(zhuǎn)為 1 后小于 c 成立;第二次進入 while 時, a < b 不成立返回 false,此時 c 為 1, 與 c 比較時,遇 < 進行隱式轉(zhuǎn)換,將 false 轉(zhuǎn)為 0,0 < 1 所以成立,這時 c --, 也為0,結束 while 循環(huán)。
第二十五題:
var length = 10;
function fn() {
console.log(this.lenght);
}
var obj = {
length: 5,
methods: function(fn) {
fn();
arguments[0]();
}
}
obj.methods(fn);
答案: 10, 1
解題:第一次執(zhí)行: fn(),表示全局調(diào)用,this指向window,所以打印 10,當?shù)诙螆?zhí)行: arguments0 時,this并非指向 obj,而是 arguments,所以打印的是 arguments 的長度 1。