-
Notifications
You must be signed in to change notification settings - Fork 1
Description
前端刷题总结
第一题
题目:
实现一个flatten函数,将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组,数组中元素仅基本类型的元素或数组,不存在循环引用的情况。
flatten2([1,2,[11],['fff',['aa',['bb']]]]) => [1, 2, 11, "fff", "aa", "bb"]
解法一:
// 解法一
function flatten(arr) {
let newarr = [];
function _flatten(arr) {
arr.forEach(item => {
if(Array.isArray(item)) {
_flatten(item)
}else {
newarr.push(item)
}
})
}
_flatten(arr)
return newarr
}
解法二:
// 解法二
function flatten2(arr) {
return arr.reduce((mero,item) => {
return mero.concat(Array.isArray(item) ? flatten2(item) : item);
},[])
}
思考:
-
刚看到这个题的时候,就想到需要判定是否是数组,递归调用
-
但是遇到一个问题,递归调用的时候,发现如果直接使用下面的一个函数,每次都会生成一个新数组覆盖了以前的数据。这样就想到了闭包,递归调用子函数,添加到父作用域上面,这样就不会每次生成一个新的数组。
function _flatten(arr) { let newarr = [] arr.forEach(item => { if(Array.isArray(item)) { _flatten(item) }else { newarr.push(item) } }) return newarr }
-
解法二的时候,不要使用arr.push,记住push函数返回的是新数组的长度,不是一个新的数组。这是一个坑。
第二题
题目:
实现一个reduce函数,作用和原生的reduce类似。
reduce(list, iteratee, [memo]),memo是reduce函数的初始值,会被每一次成功调用iteratee函数的返回值所取代 。这个迭代传递4个参数:memo,value 和 迭代的index和最后一个引用的整个 list。如果没有memo传递给reduce的初始调用,iteratee不会被列表中的第一个元素调用。第一个元素将取代memo参数传递给列表中下一个元素调用的iteratee函数。
let sum = reduce([1,2,3] ,function(memo,num) { return memo + num }, 0)
=> sum = 6
解法一:
function reduce(list, fn, memo) {
list.forEach((item, index) => {
if(memo !== undefined) {
memo = fn(memo, item, index, list)
}
else {
memo = item
}
})
return memo
}
// reduce([1,2,3,50],function(memo,num) {return memo + num})
reduce([1,2,3,50],function(memo,num) {memo[num]= num;return memo }, {})
解法二:
function iterator(list, fn, memo, index, length) {
for( ;index < length; index++) {
memo = fn(memo, list[index], index, list)
}
return memo
}
function reduce(list, fn ,memo) {
let length = list.length;
let index = 0;
if(arguments.length < 3) {
memo = list[index]
index = 1
}
return iterator(list, fn, memo, index, length )
}
reduce([1,2,3,50],function(memo,num) {return memo + num},0)
拓展:
绑定到Array.prototype
中
Array.prototype.reduce2 = function(fn,memo) {
this.forEach((item,index) => {
if(memo !== undefined) {
memo = fn(memo,item,index,this)
}
else {
memo = item
}
})
return memo
}
第三题
The goal of this exercise is to convert a string to a new string where each character in the new string is '(' if that character appears only once in the original string, or ')' if that character appears more than once in the original string. Ignore capitalization when determining if a character is a duplicate.
Examples:
"din" => "((("
"recede" => "()()()"
"Success" => ")())())"
"(( @" => "))(("
解法一
function duplicateEncode(word){
let arr =word.toLowerCase().split('');
let repeatArr = []
arr.forEach((item,idx) => {
if( idx !== arr.indexOf(item) ) {
repeatArr.push(item)
}
})
return arr.reduce((memo,item) => {
if(!repeatArr.length) {
return memo += '('
} else {
if(repeatArr.some(str => (item === str))) {
return memo += ')'
}else {
return memo += '('
}
}
}, '')
}
解法二
思路: 可以反向的找到不重复的字符串,然后取出,进行对应的替换
第四题
在不改变数组的顺序的情况下,找到数组的最小项,并删除。
Examples:
// [1,2,5,6,3] => [2,5,6,3]
// [4,5,1,3] => [4, 5, 3]
解法一
function filterMin(arr) {
let i = 0;
// 制定最小值
let min = arr[i]
let index = i ;
for(let j = i+1; j< arr.length; j++) {
if(min > arr[j]) {
min = arr[j]
index = j
}
}
return arr.filter((item,idx) => {
return idx !== index
})
}
反思: 注意要替换最小值,楼主最开始的时候也是少写了一些。(思路来源: 快速排序)
第五题
实现一个find函数,模拟原生的find函数,find(list, predicate)。
在list中逐项查找,返回第一个通过predicate迭代函数真值检测的元素值,如果没有元素通过检测则返回 undefined。 如果找到匹配的元素,函数将立即返回,不会遍历整个list。
function find(arr, fn, Athis) {
for(let i =0; i< arr.length; i++) {
if(fn.call(Athis,arr[i],i,arr)) {
return arr[i]
}
}
}
反思: 刚开始楼主想通过forEach
实现遍历,但是forEach会由于是接收一个函数,会全部遍历,并不会终止find()
的执行,最后还是必须要用for循环,等到满足条件终止函数
第六题
实现一个invoke函数,invoke(list, methodName, arguments)
在list的每个元素上执行methodName方法。 任何传递给invoke的额外参数,invoke都会在调用methodName方法的时候传递给它。
Examples
invoke([[5, 1, 7], [3, 2, 1]], 'sort');
// [[1, 5, 7], [1, 2, 3]];
invoke([[5, 1, 7], [3, 2, 1]], 'sort','reverse')
// [[7,5,1], [3,2,1]]
解法一
function invoke(list,methodName) {
let extraMethodName = Array.prototype.slice.call(arguments,2);
let newArr = [];
list.forEach(item => {
console.log(extraMethodName.length)
if(!extraMethodName.length) {
newArr.push(item[methodName]())
}else {
extraMethodName.forEach(name => {
newArr.push(item[methodName]()[name]())
})
}
})
return newArr
}
反思: ** 这里考察了我们对于对象属性的2种调用方式的熟悉程度。通过方括号调用的属性,里面必须是字符串**
// 直接通过点符号调用
var myCar = new Object();
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;
// 通过方括号来访问,里面必须是字符串
myCar["make"] = "Ford";
myCar["model"] = "Mustang";
// eg
let arr = [1,4,2]
arr['sort']() //[1,2,4]
arr.sort() // [1,2,4]