下面整理一下最近這段時間面試過程當中遇到的一些手撕的代碼題,其中有些題目遇到過不止一次,也都是比較基礎的題目,你們能夠參考一下,ps:若是你沒時間刷完大部分的leetcode題,那麼我建議優先刷一下leetcode的 熱題 HOT 100,確實很容易被問到,並且筆試裏面也會遇到,劍指也能夠,可是我沒刷過,具體的不是很瞭解。
面試
關於這個問題,在ES6中有一個新的方法arr.flat()方法,能夠直接返回降維後的數組,flat的參數爲降維的維度,默認爲一維,能夠爲數字,Infinity爲任意維,可是這個方法在低版本的瀏覽器中還不支持,因此通常會讓你寫一個原生的方法,這裏介紹幾種方法
數組
//方法一:常規方法,遞歸遍歷,判斷是否數組,須要用到額外的全局變量
var result=[]
var flat=function (arr) {
for(let i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
flat(arr[i])
}else{
result.push(arr[i]);
}
}
}
//上述方法優化
var flat=function (arr) {
var result=[]
for(let i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
result=result.concat(flat(arr[i]))
}else{
result.push(arr[i]);
}
}
return result;
}
//上述方法的簡潔寫法,利用箭頭函數
let flat = arr => arr.reduce((begin,current)=>{
Array.isArray(current)?begin.push(...flat(current)):begin.push(current);
return begin;
},[])
//方法二:使用字符串分割
var flat=function(arr){
let strarr=arr+"";
let str=strarr.split(",");
return str;
}
複製代碼
//全部順序子序列(輸出全部有序的子序列)
var subSequence=function (arr){
let res=[];
for(let i=0;i<arr.length;i++){
for(let j=i;j<arr.length;j++){
res.push(arr.slice(i,j+1))
}
}
return res;
}
console.log(subSequence([1,2,3]))
//結果爲 1 1,2 1,2,3, 2 2,3 3
//全部數組元素排列組合
// var allSubSequence=function(arr){
// let len=arr.length;
// let mark=new Array(len);
// let result=[];
// var recursion=function(arr,mark,n,i){
// if(n==i){
// let temparr=[];
// for(let k=0;k<i;k++){
// if(mark[k]==1){
// temparr.push(arr[k]);
// }
// }
// result.push(temparr);
// return;
// }
// mark[n]=0;
// recursion(arr,mark,n+1,i)
// mark[n]=1;
// recursion(arr,mark,n+1,i)
// }
// recursion(arr,mark,0,len);
// return result;
// }
// console.log(allSubSequence([1,2,3,4]));
//輸出結果爲
// [],
// [ 4 ],
// [ 3 ],
// [ 3, 4 ],
// [ 2 ],
// [ 2, 4 ],
// [ 2, 3 ],
// [ 2, 3, 4 ],
// [ 1 ],
// [ 1, 4 ],
// [ 1, 3 ],
// [ 1, 3, 4 ],
// [ 1, 2 ],
// [ 1, 2, 4 ],
// [ 1, 2, 3 ],
// [ 1, 2, 3, 4 ]
//原理:
//原理,使用二進制的排列組合來實現
//將a,b,c,d 分別以二進制佔位符表示,0即表示不存在,1表示不存在,mark數組即用來存儲這個佔位符
//如0000則表示空集,1111表示集合{a,b,c,d},0001表示{d},0110表示{b,c}
//本質就是將0000按二進制加到1111,每加1就輸出一次其表示的數
//遞歸的原理圖以下,當只有abc三個數時
// 0
// 0
// 1
// 0
// 0
// 1
// 1
// start
// 0
// 0
// 1
// 1
// 0
// 1
// 1
複製代碼
var result=[];
var results=[];
var doExchange=function (arr, depth) {
for (let i = 0; i < arr[depth].length; i++) {
result[depth] = arr[depth][i];
if (depth !== arr.length - 1) {
doExchange(arr, depth + 1)
} else {
results.push(result.join(" ").split(" "))
}
}
}
doExchange([[1,2,3],[4,5],[6,7]],0)
for(let i=0;i<results.length;i++){
for(let j in results[i]){
results[i][j]=parseInt(results[i][j])
}
}
console.log(results)
//結果:
// [ 1, 4, 6 ],
// [ 1, 4, 7 ],
// [ 1, 5, 6 ],
// [ 1, 5, 7 ],
// [ 2, 4, 6 ],
// [ 2, 4, 7 ],
// [ 2, 5, 6 ],
// [ 2, 5, 7 ],
// [ 3, 4, 6 ],
// [ 3, 4, 7 ],
// [ 3, 5, 6 ],
// [ 3, 5, 7 ]
複製代碼
這裏其實考察的是函數中this的指向問題,這裏用到了前文提到過的一個知識點 在js部分-ES6新增-函數相關擴展方法-普通函數中的this的四種調用模式
瀏覽器
//方法一:使用函數的方式實現
function Person(val){
this.name="admin";
this.getName=function(){
return this.name;
}
this.setName=function(val){
this.name=val;
}
}
var per=new Person();
console.log(per.name)//admin
console.log(per.getName())//admin
per.setName(111)
console.log(per.getName())//111
//方法二:使用對象的方式實現(這種方式不能new一個實例)
var Person={
name:"admin",
getName(){
return this.name;
},
setName(val){
this.name=val
}
}
console.log(Person.name)//admin
console.log(Person.getName())//admin
Person.setName("111")
console.log(Person.getName())//111
//方法三:使用原型鏈的按時實現
function Person(){ }
Person.prototype.name="admin";
Person.prototype.getName=function(){
return this.name;
};
Person.prototype.setName=function(val){
this.name=val;
};
var per=new Person();
console.log(per.name)//admin
console.log(per.getName())//admin
per.setName(111)
console.log(per.getName())//111
複製代碼
toString()會把數據類型轉換成string類型,也就是說無論原來是什麼類型,轉換後一概是string類型
valueOf()會把數據類型轉換成原始類型,也就是說原來是什麼類型,轉換後仍是什麼類型,日期類型除外
markdown
let a={
i:1,
valueOf(){
return a.i++;
}
}
console.log(a==1&&a==2) //true
let b={
i:1,
toString(){
return b.i++;
}
}
console.log(b==1&&b==2) //true
複製代碼
//方法一:ES6 let 塊級做用域
//注意:這裏若是使用var的話,會每一個一秒輸出一個5,輸出5個5
for(let i = 1; i <5; i++){
setTimeout(function () {
console.log(i);
},1000*i);
}
//方法二:ES5 閉包 匿名函數and函數自動執行
// (function(i){})(i) 其中第一個()返回一個匿名函數,第二()起到當即執行的做用
for (var i = 1; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 1000 * i);
})(i);
}
複製代碼
/*
*fn --> 須要防抖的函數;
*delaytime --> 毫秒數,防抖所需期限值;
*/
//防抖
//原理:當持續觸發事件時,必定時間段內沒有再觸發事件,事件處理函數纔會執行一次,若是設定的時間到來以前,又一次觸發了事件,
//就從新開始延時。
function debounce(fn,delaytime){
let timer = null
return function(){
if(timer){
//進入這裏說明當前存在一個執行過程,而且同時又執行了一個相同事件,故取消當前的執行過程
clearTimeout(timer)
}
timer = setTimeout(fn,delaytime)
}
}
function show_scrollPosition(){
var scrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
console.log("當前滾動條位置爲:",scrollPosition);
}
window.onscroll = debounce(show_scrollPosition,1000)
//節流
//原理:規定一個期限時間,在該時間內,觸發事件的回調函數只能執行一次,若是期限時間內回調函數被屢次觸發,則只有一次能生效。
function throttle(fn, delay) {
let last_time
let timer = null
return function () {
let cur_time = new Date().getTime()
if (last_time && cur_time < last_time + delay) {
//若爲真,則表示上次執行過,且在期限值範圍內
clearTimeout(timer)
timer = setTimeout(() => {
fn();
last_time = cur_time
}, delay)
} else {
last_time = cur_time;
fn();
}
}
}
function show_scrollPosition() {
var scrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
console.log("當前滾動條位置爲:", scrollPosition);
}
window.onscroll = throttle(show_scrollPosition, 1000)
複製代碼
function add(val){
var rs = function(oval){
return add(val + oval);
}
rs.toString = function(){
return val;
}
return rs;
}
console.log(add(1)(2)(3) == 6);
複製代碼