面试题-代码题

161 阅读6分钟

把遇到的记录下来,如果大家手里也有手写代码的题可以分享哈,会不断的更新

字符串相关

String.trim()实现

let str='  1 2 3 5  ' //1 2 3 5

let start,end
for(let i=0;i<str.length;i++){
    if(str[i]!==' '){
        start=i
        break;
    }
}
for(let i=str.length-1;i>0;i--){
    if(str[i]!==' '){
        end=i
        break;
    }
}
let res=str.substring(start,end+1)

new 函数实现

function newInstance(constructor, ...args) {
  // 创建一个空对象,且 __proto__ 指向 constructor.prototype
  const obj = Object.create(constructor.prototype);
  // 执行构造函数并绑定 this 到新对象上
  const result = constructor.apply(obj, args);
  // 如果构造函数返回了一个对象,则返回该对象
  if (result && (typeof result === "object" || typeof result === "function")) {
    return result;
  }
  // 否则返回新对象
  return obj;
}

// 示例使用
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, I'm ${this.name}.`);
};

const person1 = newInstance(Person, "Allen");
person1.greet(); // 输出 "Hello, I'm Allen."

手写intanceof实现原理

function myInstanceof(left,right){
    //获取对象的原型
    let proto=Object.getPrototypeOf(left)
    //获取构造函数的prototype对象
    let prototype=right.prototype
    //判断构造函数的prototype对象是否在对象的原型链上
    while(true){
        if(!proto) return false
        if(proto===prototype) return true
        //如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法来获取指定对象的原型
        proto=Object.getPrototypeOf(proto)
    }
}

数组去重

方法一 原型上手写方法

Array.prototype.unique = function() {  
    let uniqueArray = [];  
    for(let i = 0; i < this.length; i++) {  
        if(uniqueArray.indexOf(this[i]) === -1) {  
            uniqueArray.push(this[i]);  
        }  
    }  
    return uniqueArray;  
}

let array = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArray = array.unique();  
console.log(uniqueArray); // 输出 [1, 2, 3, 4, 5]

方法二 es6 Set

function unique(arr) {  
    return Array.from(new Set(arr));  
}  
  
let array = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArray = unique(array);  
console.log(uniqueArray); // 输出 [1, 2, 3, 4, 5]

方法三 对象key唯一

function unique(arr) {  
    let hashTable = {};  
    let uniqueArray = [];  
    for(let i = 0; i < arr.length; i++) {  
        if(!hashTable[arr[i]]) {  
            hashTable[arr[i]] = true;  
            uniqueArray.push(arr[i]);  
        }  
    }  
    return uniqueArray;  
}  
  
let array = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArray = unique(array);  
console.log(uniqueArray); // 输出 [1, 2, 3, 4, 5]

方法四 includes

function unique(arr) {
  let uniqueArray = [];
  for (let i = 0; i < arr.length; i++) {
    if (!uniqueArray.includes(arr[i])) {
        uniqueArray.push(arr[i]);
    }
  }
  return uniqueArray;
}

let array = [1, 2, 2, 3, 4, 4, 5,[1,2,3]];
let uniqueArray = unique(array);
console.log(uniqueArray); 

数组扁平化

//输入 var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]]; 
//输出 [1,2,3,4,5,6,7,8,9,10,11,12]

方法一 普通遍历

function flat(arr){
	if(Object.prototype.toString.call(arr) != "[object Array]"){return false};
	let res = [];
	for(var i=0;i<arr.length;i++){
		if(arr[i] instanceof Array){
			res = res.concat(flat(arr[i]))
		}else{
			res.push(arr[i])
		}
	}
	return res;
};
var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]];
flat(arr);
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

方法二(递归+扩展运算符)

function flat(arr){
	if(Object.prototype.toString.call(arr) != "[object Array]"){return false};
	let res=[];
    arr.map(item=>{
        if(item instanceof Array){
            res.push(...flat(item));
        }else{
            res.push(item)
        }
    });
    return res;
};	
var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]];
flat(arr);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

方法三 (递归+reduce)

function flat(arr){
	if(Object.prototype.toString.call(arr) != "[object Array]"){return false};
	
	let res = arr.reduce((prev,cur)=>{
	    return prev.concat(Array.isArray(cur) ? flat(cur) : cur)
	},[])
	return res;
};
var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]];
flat(arr);

// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

方法四 (toString+split) 推荐

var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]];
var arr1 = arr.toString().split(',').map((val)=>{
            return parseInt(val)
});
console.log(arr1);
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]


方法五 递归

    let arr = [[1, 2], 3, [[[4], 5]]]; 
    function flat(arr) {
        return [].concat(
            ...arr.map(x => Array.isArray(x) ? flat(x) : x)
        )
    };
    flat(arr);// [1,2,3,4,5]

方法六 (递归+扩展运算符)

function flat(arr){
	if(Object.prototype.toString.call(arr) != "[object Array]"){return false};
	let res=[];
    arr.map(item=>{
        if(item instanceof Array){
            res.push(...flat(item));
        }else{
            res.push(item)
        }
    });
    return res;
};	
var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]];
flat(arr);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

查找

实现一个查找文章中出现频率最高的单词的方法

function findMostFrequentWord(text) {  
// 将文本转换为小写并分割为单词数组  
let words = text.toLowerCase().split(/\W+/);  
  
// 创建一个对象来存储每个单词的频率  
let wordFreq = {};  
  
// 遍历单词数组并计算每个单词的频率  
for (let i = 0; i < words.length; i++) {  
if (wordFreq[words[i]]) {  
wordFreq[words[i]]++;  
} else {  
wordFreq[words[i]] = 1;  
}  
}  
  
// 创建一个数组来存储频率最高的几个单词  
let topWords = Object.keys(wordFreq).sort((a, b) => wordFreq[b] - wordFreq[a]);  
  
// 返回频率最高的单词  
return topWords[0];  
}  
  
// 测试代码  
let text = "The quick brown fox jumps over the lazy dog. The dog is lazy. Fox jumps over dog.";  
console.log(findMostFrequentWord(text)); // 输出 "the"

call apply bind

const person1={
    name:'ludan',
    say:function(n1,n2){
        console.log(this.name,n1+n2)
    }
}
const person2={
    name:'123'
}


Function.prototype.myCall=function(context,...args){
    if(typeof this!='function'){
        throw new TypeError('error')
    }
    context=context||window
    context.fn=this
    let result=context.fn(...args)
    delete context.fn
    return result
}
// const arr=[2,3,4,5,6]
person1.say.myCall(person2)

apply

const person1={
    name:'ludan',
    say:function(n1,n2){
        console.log(this.name,n1+n2)
    }
}
const person2={
    name:'123'
}


Function.prototype.myApply=function(context,arrArgs){
    if(typeof this!='function'){
        throw new TypeError('error')
    }
    context=context||window
    context.fn=this
    let result=context.fn(...arrArgs)
    delete context.fn
    return result
}
const arr=[2,3,4,5,6]
person1.say.myApply(person2,[10,20])

bind

const person1={
    name:'ludan',
    say:function(n1,n2){
        console.log(this.name,n1+n2)
    }
}
const person2={
    name:'123'
}

Function.prototype.myBind = function(context, ...args) {
    // 判断调用对象是不是函数
    if(typeof this !== "function"){
        throw new TypeError('error');
    }
    // 如果没有传入上下文对象,则默认为全局对象window
    context = context || window
    // 保存原始函数的引用,this就是要绑定的函数
    const _this = this
    // 返回一个新的函数作为绑定函数
    return function fn(...innerArgs) {
        // 判断返回出去的函数有没有被new
        if(this instanceof fn){
            return new _this(...args, ...innerArgs);
        }
        // 使用 apply 方法将原函数绑定到指定的上下文对象上
        return _this.apply(context, [...args, ...innerArgs]);
    };
};

let person=person1.say.myBind(person2)
person(1,2)

防抖 节流

防抖(debounce)是一种在一定时间内只触发一次的技术,常用于处理高频事件,例如输入框的连续搜索。以下是一个适合面试的防抖代码示例:

function debounce(func, wait) {  
  let timeout;  
  return function() {  
    clearTimeout(timeout);  
    timeout = setTimeout(() => {  
      func.apply(this, arguments);  
    }, wait);  
  };  
}

解释:

  1. debounce 函数接受两个参数:要防抖的函数 func 和等待时间 wait
  2. 函数内部创建一个 timeout 变量,用于存储定时器的引用。
  3. 返回一个新函数,该函数在调用时首先会清除之前的定时器,然后设置一个新的定时器。
  4. 在定时器回调中,调用原始函数 func 并传入当前上下文和参数。
  5. 在等待时间 wait 内,如果再次调用返回的函数,则清除之前的定时器并重新设置。
  6. 当等待时间过后,如果之前没有再次调用返回的函数,则定时器回调执行原始函数 func

该代码实现了防抖功能,并在等待时间内只触发一次原始函数。如果需要在面试中展示自己的代码能力,可以将此代码写在纸上或黑板上,并解释每一步的操作和实现原理。

节流 第一版

节流(throttling)是一种限制单位时间内触发次数的技术,常用于处理高频事件,例如滚动事件。以下是一个适合面试的节流代码示例:

function throttle(func, limit) {  
  let lastCall = 0;  
  return function() {  
    const now = Date.now();  
    if (now - lastCall < limit) {  
      return;  
    }  
    lastCall = now;  
    func.apply(this, arguments);  
  };  
}

解释:

  1. throttle 函数接受两个参数:要节流的函数 func 和限制时间间隔 limit
  2. 函数内部创建一个 lastCall 变量,用于记录上次调用的时间戳。
  3. 返回一个新函数,该函数在调用时首先获取当前时间戳 now,然后与上次调用时间戳 lastCall 进行比较。
  4. 如果当前时间与上次调用时间差小于限制时间间隔 limit,则不执行任何操作,直接返回。
  5. 如果当前时间与上次调用时间差大于等于限制时间间隔 limit,则更新 lastCall 为当前时间戳,并调用原始函数 func,传入当前上下文和参数。
  6. 该代码实现了节流功能,在限制时间间隔内只触发一次原始函数。如果需要在面试中展示自己的代码能力,可以将此代码写在纸上或黑板上,并解释每一步的操作和实现原理。

第二版定时器

function throttle(func, limit) {  
  let timer = null;  
  return function() {  
    if (!timer) {  
      timer = setTimeout(() => {  
        func.apply(this, arguments);  
        timer = null;  
      }, limit);  
    }  
  };  
}

解释:

  1. throttle 函数接受两个参数:要节流的函数 func 和限制时间间隔 limit
  2. 函数内部创建一个 timer 变量,用于存储定时器的引用。
  3. 返回一个新函数,该函数在调用时会首先检查 timer 是否为空。
  4. 如果 timer 为空,则设置一个定时器,在 limit 时间后调用原始函数 func,并传入当前上下文和参数。
  5. 如果 timer 不为空,则表示已经在等待时间内触发了多次函数调用,因此不执行任何操作。
  6. 当定时器回调执行完原始函数 func 后,将 timer 设置为空,以便在下一次触发时重新设置定时器。

手写倒计时

let countdown = 10;  
function count() {  
  console.log(countdown);  
  if (countdown-- !== 0) {  
    setTimeout(count, 1000);  
  } else {  
    console.log('倒计时结束');  
  }  
}  
count();

前端js--30-计时器

// setTimeout
function count(start, end) {
    if(start <= end){
        console.log(start);
        start++;
        st = setTimeout(function(){count(start, end)}, 100);
    }
    return {
        cancel: function(){clearTimeout(st);}
    }

手写深度拷贝

  //使用递归实现深拷贝
     function deepClone(obj) {
         //判断拷贝的obj是对象还是数组
         var objClone = Array.isArray(obj) ? [] : {};
         if (obj && typeof obj === "object") { //obj不能为空,并且是对象或者是数组 因为null也是object
             for (key in obj) {
                 if (obj.hasOwnProperty(key)) {
                     if (obj[key] && typeof obj[key] === "object") { //obj里面属性值不为空并且还是对象,进行深度拷贝
                         objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
                     } else {
                         objClone[key] = obj[key]; //直接拷贝
                     }
                 }
             }
         }
         return objClone;
     }


let obj = {
  a: [1, 2, 3,[2,3,5]],
  b: 2,
  c: 3,
  d: { a: "1", b: "2" },
};

let a=deepClone(obj)
console.log(a)

手撕快排

function quickSort(arr, left = 0, right = arr.length - 1) {  
    if (left < right) {  
        let pivotIndex = partition(arr, left, right);  
        quickSort(arr, left, pivotIndex - 1);  
        quickSort(arr, pivotIndex + 1, right);  
    }  
    return arr;  
}  
  
function partition(arr, left, right) {  
    let pivot = arr[right];  
    let i = left;  
    for (let j = left; j < right; j++) {  
        if (arr[j] < pivot) {  
            [arr[i], arr[j]] = [arr[j], arr[i]];  
            i++;  
        }  
    }  
    [arr[i], arr[right]] = [arr[right], arr[i]];  
    return i;  
}
let arr = [9, -3, 5, 2, 6, 8, -6, 1, 3];  
console.log(quickSort(arr)); // [-6, -3, 1, 2, 3, 5, 6, 8, 9]

利用setTimeout实现setInterval

function setIntervalUsingSetTimeout(callback, delay) {  
    function loop() {  
        callback();  
        setTimeout(loop, delay);  
    }  
    setTimeout(loop, delay);  
}  
  
// 使用方式  
setIntervalUsingSetTimeout(function() {  
    console.log("这是每隔两秒执行一次的消息");  
}, 2000);

EventBus

class EventBus {
  constructor() {
    this.bus = {};
  }
  $on(name, fn) {
    if (this.bus[name]) {
      this.bus[name].push(fn);
    } else {
      this.bus[name] = [fn];
    }
  }
  $emit(name, ...args) {
    if (this.bus[name]) {
      let tasks = this.bus[name].slice();
      tasks.forEach((callback) => {
        callback(...args);
      });
    }
  }
  $off(name, fn) {
    let task = this.bus[name];
    if (task) {
      this.bus[name] = this.bus[name].filter(
        (cb) => cb !== fn
      ); // 过滤掉要取消的回调函数
    }
  }
}

// 创建全局事件总线对象
const eventBus = new EventBus();

const callback1 = (data) => {
  console.log("Callback 1:", data);
};

const callback2 = (data) => {
  console.log("Callback 2:", data);
};

// 订阅事件
eventBus.$on("event1", callback1);
eventBus.$on("event1", callback2);

// 发布事件
eventBus.$emit("event1", "Hello, world!");

// 输出:
// Callback 1: Hello, world!
// Callback 2: Hello, world!

// 取消订阅事件
eventBus.$off("event1", callback1);

// 发布事件
eventBus.$emit("event1", "Goodbye!");

实现一个简单的双向绑定


<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>

    <body>
        <input id="inputElement" type="text">
        <div id="outputElement"></div>
    </body>

</html>
<script>
    let state = {}
    const inputElement = document.getElementById('inputElement')
    const outputElement = document.getElementById('outputElement')

    Object.defineProperty(state, 'value', {
        configurable: true,
        enumerable: true,
        get: () => {
            console.log('get value')
        },
        set: (newValue) => {
            console.log('set value: ', newValue)
            inputElement.value = newValue
            outputElement.innerHTML = newValue
        }
    })

    inputElement.addEventListener('keyup', (event) => {
        state.value = event.target.value
    })
</script>

coder.sleep().print1().print2()

function Coder () {
    
}
Coder.prototype = {
    sleep() {
        console.log(`sleep`);
        return this
    },
    print1() {
        console.log('print1!');
        return this
    },
    print2() {
        console.log('print2');
        return this
    },
}
const coder = new Coder()
coder.sleep().print1().print2()

类的实现

class Coder {  
  
  print1() {  
    console.log("Printing from print1 method");  
    return this;  
  }  
  
  print2() {  
    console.log("Printing from print2 method");  
    return this;  
  }  
  
  sleep() {  
    console.log("sleep");  
    return this;  
  }  
}  
  
const coder = new Coder();
coder.sleep().print1().print2()

实现代码3秒后执行下面代码

const arr = [[1,2],[3,4],[5,6],[7,8]]
      function arrreadce(arr){
        return arr.reduce((pre,cur)=>{
          return pre.concat(Array.isArray(cur)?arrreadce(cur):cur)
        },[])
      }
function delay(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, time)
  })
}
(async function (){
    await delay(3000)
    console.log('ok')
})()

手写获取url 获取链接参数

// 输入:    www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key

// 输出:    [1, 2, 3]

function getUrlParam(sUrl, sKey) {
    var paramArr = sUrl.split('?')[1].split('#')[0].split('&'); // 取出每个参数的键值对放入数组
    const obj = {};
    paramArr.forEach(element => {
        const [key, value] = element.split('=');  // 取出数组中每一项的键与值
        if(obj[key] === void 0){   // 表示第一次遍历这个元素,直接添加到对象上面
            obj[key]=value
        } else{
        obj[key]=[].concat(obj[key],value); // 表示不是第一次遍历说明这个键已有,通过数组存起来。
    }});
    return sKey===void 0? obj:obj[sKey]||''   // 如果该方法为一个参数,则返回对象。
    //如果为两个参数,sKey存在,则返回值或数组,否则返回空字符。
}
let url = 'https://example.com/?name=John&age=30&city=New%20York';  
  
let params = url.split('?')[1]; // 获取URL中问号后的部分  
  
let extractParams = {};  
  
params.split('&').forEach(function(param) { // 按照'&'分割每个参数  
let [key, value] = param.split('='); // 按照'='分割每个参数中的键和值  
extractParams[decodeURIComponent(key)] = decodeURIComponent(value); // 对键和值进行解码  
});  
  
console.log(extractParams); // { name: 'John', age: '30', city: 'New York' }


或者
let url = 'https://example.com/?name=John&age=30&city=New%20York';  
  
let params = (new URL(url)).searchParams;  
  
let extractParams = {};  
  
for (let [key, value] of params) {  
extractParams[key] = value;  
}  
   
console.log(extractParams);  // { name: 'John', age: '30', city: 'New York' }


手写 Class 实现简易版发布订阅过程

    

class PubSub {  
  constructor() {  
    this.subscribers = {};  
  }  
  
  // 注册订阅者  
  subscribe(event, callback) {  
    if (!this.subscribers[event]) {  
      this.subscribers[event] = [];  
    }  
    this.subscribers[event].push(callback);  
    console.log(`订阅 ${event} 事件`);  
  }  
  
  // 注销订阅者  
  unsubscribe(event, callback) {  
    if (this.subscribers[event]) {  
      this.subscribers[event] = this.subscribers[event].filter(cb => cb !== callback);  
    }  
    console.log(`取消订阅 ${event} 事件`);  
  }  
  
  // 发布事件  
  publish(event, data) {  
    if (this.subscribers[event]) {  
      this.subscribers[event].forEach(callback => callback(data));  
    }  
    console.log(`发布 ${event} 事件,传递数据 ${data}`);  
  }  
}

const pubsub = new PubSub();  
  
// 注册订阅者  
pubsub.subscribe('event1', () => console.log('收到 event1 事件'));  
pubsub.subscribe('event2', (data) => console.log(`收到 event2 事件,传递数据 ${data}`));  
  
// 发布事件  
pubsub.publish('event1', 'Hello World!');  
pubsub.publish('event2', 'Goodbye World!');  
  
// 注销订阅者  
pubsub.unsubscribe('event1', () => console.log('收到 event1 事件'));

实现一个函数 find(obj, str),满足:如var obj = {a:{b:{c:1}}};find(obj,'a.b.c') //返回1find(obj,'a.d.c') //返回undefined

第一版有问题只能是固定的输出结果

var obj = {
    a:{
        b:{
      
      c:1
        }
    }
}
 
var str = 'a.b.c';

const find = (obj,str) => {
  let arr = []
  for (const key in str) {
    if (Object.hasOwnProperty.call(str, key)) {
      if (str[key]!= '.') {
        arr.push(str[key])
      }
    }
  }
  try {
    return `${obj[arr[0]][arr[1]][arr[2]]}`
  } catch (error) {
    return undefined
  }
}

find(obj,'a.b.c')
find(obj,'a.d.c')
find(obj,null)

第二版升级版

function find(obj,str){
    const arr=str?.split('.')||[]
    let res=obj
    for(let i=0;i<arr.length;i++){
        res=res[arr[i]]
        if (res===undefined) break;
    }
    return res
}
const objs={a:{b:{c:1}}}
console.log(find(objs,'a.b'))

如何提取高度嵌套的对象里的指定属性

要提取高度嵌套的对象中的指定属性,您可以使用递归来遍历对象并提取所需的属性。以下是一个示例函数,它接受两个参数:要提取的属性名称和要搜索的对象。

function extractNestedProperty(prop, obj) {  
  let result = obj;  
  
  // 递归遍历对象  
  for (let part of prop.split('.')) {  
    if (result[part] !== undefined) {  
      result = result[part];  
    } else {  
      return undefined;  
    }  
  }  
  
  return result;  
}

const nestedObj = {  
  a: {  
    b: {  
      c: 123,  
      d: {  
        e: 456,  
        f: {  
          g: 789  
        }  
      }  
    },  
    h: {  
      i: {  
        j: 'abc'  
      }  
    }  
  }  
};  
  
console.log(extractNestedProperty('a.b.c', nestedObj)); // 输出:123  
console.log(extractNestedProperty('a.b.d.e', nestedObj)); // 输出:456  
console.log(extractNestedProperty('a.h.i.j', nestedObj)); // 输出:'abc'  
console.log(extractNestedProperty('x.y', nestedObj)); // 输出:undefined

once

export function once (fn) {
  // 利用闭包判断函数是否执行过
  let called = false
  return function () {
    if (!called) {
      called = true
      fn.apply(this, arguments)
    }
  }
}

函数柯里化

console.log(curriedAdd(1)(2)(3)) // 输出 6 
console.log(curriedAdd(1, 2)(3)) // 输出 6 
console.log(curriedAdd(1)(2, 3)) // 输出 6

如何翻转一个字符串

function reverseString(str) {  
return str.split('').reverse().join('');  
}  
  
let str = "Hello, World!";  
console.log(reverseString(str)); // 输出: "!dlroW ,olleH"

找出任意html中的所有不重复的html的标签

// 获取文档中的所有标签  
let tags = [...document.body.getElementsByTagName('*')].map(el => el.tagName);  
  
// 移除重复的标签  
let uniqueTags = [...new Set(tags)];  
  
// 输出不重复的标签  
console.log(uniqueTags);

手写实现数组map 和数组filter

map 原型链实现

Array.prototype._map=function(){
    var newArr=[]
    for(var i=0;i<this.length;i++){
       newArr.push(fn(this[i],i)) 
    }
    return newArr
}
console.log(arr._map((v)=>v+1))
function map(array, callback) {  
    let result = [];  
    for(let i = 0; i < array.length; i++) {  
        result.push(callback(array[i], i, array));  
    }  
    return result;  
}  
  
// 使用示例:  
let arr = [1, 2, 3, 4, 5];  
let squared = map(arr, num => num * num);  
console.log(squared); // 输出:[1, 4, 9, 16, 25]

filter

function filter(array, callback) {  
    let result = [];  
    for(let i = 0; i < array.length; i++) {  
        if(callback(array[i], i, array)) {  
            result.push(array[i]);  
        }  
    }  
    return result;  
}  
  
// 使用示例:  
let arr = [1, 2, 3, 4, 5];  
let even = filter(arr, num => num % 2 === 0);  
console.log(even); // 输出:[2, 4]
Array.prototype._filter=function(){
    var newArr=[]
    for(var i=0;i<this.length;i++){
        if(fn(this[i])){
            newArr.push((this[i]) 
        }
    }
    return newArr
}
console.log(arr._filter((v)=>v+1))

数组

给定一个整数数组,找到数组中的最大值并返回它的索引

function findMaxIndex(arr) {
  let maxIndex = 0;
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > arr[maxIndex]) {
      maxIndex = i;
    }
  }
  return maxIndex;
}
findMaxIndex([1,2,3,55,7])

原型链上实现reduce

for

Array.prototype.myReduce = function (fn, initval) {
  var arr = this;
  if (typeof fn != "function") {
    throw new TypeError("error");
  }
  //初始没值传入,使用数据第1个
  if (typeof initval === "undefined") {
    initval = arr[0];
    for (var i = 1; i < arr.length; i++) {
      initval = fn(initval, arr[i], i, arr);
    }
  } else {
    //传入有值函数传入用初始值
    for (var i = 0; i < arr.length; i++) {
      initval = fn(initval, arr[i], i, arr);
    }
  }
  return initval;
};

let arrs = [1, 2, 3];
let a = arrs.myReduce((initval, temp) => {
  return initval + temp;

map

Array.prototype.myReduce = function (fn, initval) {
  if (typeof fn !== "function") {
    throw new TypeError("error");
  }
  let arr = this;
  let accumulator = initval;
  let currentValue = initval;
  //判断默认值没有传值
  if (typeof initval === "undefined") {
    accumulator = arr[0];
    currentValue = arr[1];
    startIndex = 1;
  } else {
    if (arr.length === 0) {
      return initval;
    }
    //判断传值了
    accumulator = initval;
    currentValue = arr[0];
    startIndex = 0;
  }
  arr.map((item, index) => {
    if (index < startIndex) {
      return;
    }
    currentValue = item;
    accumulator = fn(accumulator, currentValue, index, arr);
  });
  return accumulator;
};
let arrs = [1,2,3];
let a = arrs.myReduce((initval, temp) => {
  return initval + temp;
},1);
console.log(a)

leetcode

现在面试要求特别高了,需要有算法能力,决定抽时间来刷lc

数组相关的

找出数组中出现次数1次的

一个由数字组成的数组,其中有一个数字出现1次,其它数字都出现了2次,编写方法 findSingleNumber,快速找出出现1次的数字。 测试用例: console.log(findSingleNumber([1, 0, 2, 4, 5, 2, 4, 1, 0])); // 输出:5

思路:利用对象来帮助,遍历的时候把每个数据做为对象的key来进行判断,如果出现过就把值设置2,没有出现过就设置成1

var singleNumber = function(nums) {
    let obj={}
    for(let i=0;i<nums.length;i++){
        if(obj[nums[i]]){
            obj[nums[i]]=2
        }else{
            obj[nums[i]]=1
        }
    }
    for(key in obj){
        if(obj[key]===1) return key
    }
};
singleNumber([4,1,2,1,2])

也有可能同时出现多个1次的,那就可以放一个数组里接下来特殊需求的操作

image.png

两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

 

示例 1:

输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入: nums = [3,2,4], target = 6
输出: [1,2]

这种题一般就是数组前一位和后一位相加来做对比,那这种就最简单的思路就是2层for循环

var twoSum = function(nums, target) {
    let start=nums[0]
    let res
    for(let i=0;i<nums.length;i++){
        for(let j=i+1;j<nums.length;j++){
            if(Number(nums[i])+Number(nums[j])==target){
                res=[i,j]
                break;
            }
        }
    }
    return res
};
twoSum([2,7,11,15],9)

第二种解法

let nums=[11,2,7,15]
let target=9
function fn(nums,target){
    let map=new Map()
    nums.forEach((value,index)=>{
        map.set(value,index)
    })
    //把map改造成{11 => 0, 2 => 1, 7 => 2, 15 => 3}
    for(let i=0;i<nums.length;i++){
        let j=map.get(target-nums[i]) //这里返回符合数据的下标
        if(j!=undefined){
            return [i,j]
        }
        
    }
    return []
}
fn(nums,9)

第三种

let nums=[11,2,7,15]
let target=9
function fn(nums,target){
    let arr=nums.map((value,index)=>{
        return {value,index}
    })
    arr.sort((i,j)=>i.value-j.value)
    console.log(arr)
    let i=0,j=nums.length-1
    while (i!=j) {
        if(arr[i].value+arr[j].value===target){
            return [arr[i].index,arr[j].index]
        }else if(arr[i].value+arr[j].value>target){
            j--
        }else{
            i++
        }
    }
    
}
fn(nums,9)

把字符串切成数组

'abcdefghi' 三三分组,结果:['abc', 'def', 'ghi']

var divideString = function (s, k) {

  let result = []
  for (let i = 0; i < s.length; i++) {
    const str = s.slice(i * k, (i + 1) * k)
    const l = str.length
    if (l === k) {
      result.push(str)
    }
  }
  return result
}
divideString('abcdefghi',3)