手写面试题

#手写面试题

class Scheduler {
  constructor() {
    this._max = 2;
    this.unwork = [];
    this.working = [];
  }
  add(asyncTask) {
    return new Promise((resolve) => {
      asyncTask.resolve = resolve;
      if(this.working.length < this._max) {
        this.runTask(asyncTask);
      } else {
        this.unwork.push(asyncTask);
      }
    })
  }

  runTask(asyncTask) {
    this.working.push(asyncTask);
    asyncTask().then(() => {
      asyncTask.resolve();      //asyncTask异步任务完成以后,再调用外层Promise的resolve以便add().then()的执行
      var index = this.working.indexOf(asyncTask);
      this.working.splice(index,1);   //从正在进行的任务队列中删除
      if(this.unwork.length > 0) {
        this.runTask(this.unwork.shift());  
      }
    })

//手写promise
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    // 存放成功的回调
    this.onResolvedCallbacks = [];
    // 存放失败的回调
    this.onRejectedCallbacks= [];

    let resolve = (value) => {
      if(this.status ===  PENDING) {
        this.status = FULFILLED;
        this.value = value;
        // 依次将对应的函数执行
        this.onResolvedCallbacks.forEach(fn=>fn());
      }
    } 
    let reject = (reason) => {
      if(this.status ===  PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        // 依次将对应的函数执行
        this.onRejectedCallbacks.forEach(fn=>fn());
      }
    }
    try {
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }

    if (this.status === REJECTED) {
      onRejected(this.reason)
    }

    if (this.status === PENDING) {
      // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value)
      });

      // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
      this.onRejectedCallbacks.push(()=> {
        onRejected(this.reason);
      })
    }
  }
}
// 发布订阅模式
class EventEmitter {
  constructor() {
    // 事件对象,存放订阅的名字和事件  如:  { click: [ handle1, handle2 ]  }
    this.events = {};
  }
  // 订阅事件的方法
  on(eventName, callback) {
    if (!this.events[eventName]) {
      // 一个名字可以订阅多个事件函数
      this.events[eventName] = [callback];
    } else {
      // 存在则push到指定数组的尾部保存
      this.events[eventName].push(callback);
    }
  }
  // 触发事件的方法
  emit(eventName, ...rest) {
    // 遍历执行所有订阅的事件
    this.events[eventName] &&
      this.events[eventName].forEach(f => f.apply(this, rest));
  }
  // 移除订阅事件
  remove(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(
        f => f != callback
      );
    }
  }
  // 只执行一次订阅的事件,然后移除
  once(eventName, callback) {
    // 绑定的时fn, 执行的时候会触发fn函数
    const fn = (...rest) => {
      callback.apply(this, rest) // fn函数中调用原有的callback
      this.remove(eventName, fn) // 删除fn, 再次执行的时候之后执行一次
    }
    this.on(eventName, fn)
  }
}
//手写call
Function.prototype.myCall = function(context, ...args) {
  // 判断是否是undefined和null
  if (typeof context === 'undefined' || context === null) {
    context = window
  }
  let fnSymbol = Symbol()
  context[fnSymbol] = this
  let fn = context[fnSymbol] (...args)
  delete context[fnSymbol] 
  return fn
}

Function.prototype.myApply = function(context, args) {
  // 判断是否是undefined和null
  if (typeof context === 'undefined' || context === null) {
    context = window
  }
  let fnSymbol = Symbol()
  context[fnSymbol] = this
  let fn = context[fnSymbol] (...args)
  return fn
}

Function.prototype.myBind = function(context) {
// 判断是否是undefined和null
    if (typeof context === "undefined" || context === null) {
    	context = window;
    }
    self = this;
    return function(...args) {
    	return self.apply(context, args);
    }
}

1. 递归循环数组,如果循环元素还是数组,继续递归调用方法
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        }
        else {
            result.push(arr[i])
        }
    }
    return result;
}
console.log(flatten(arr))
2. reduce
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}
console.log(flatten(arr))
3. 扩展运算符
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
    }
    return arr;
}
console.log(flatten(arr))
4. flat
参考数组原型的方法falt
var arr = [1, [2, [3, 4]]];
var result = arr.flat(Infinity);
console.log(result);

转化为驼峰命名
var s1 = "get-element-by-id" // 转化为 getElementById
var f = function(s) {
    return s.replace(/-\w/g, function(x) {
        return x.slice(1).toUpperCase();
    })
}
//深拷贝
let obj1 = {  a: 0,
              b: { c: 0 }
            };
let obj2 = JSON.parse(JSON.stringify(obj1));
function deepCopy(object) {
  if (!object || typeof object !== "object") return;
  let newObject = Array.isArray(object) ? [] : {};
  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      newObject[key] =
        typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
    }
  }
  return newObject;
}
//手写 Object.create
//将传入的对象作为原型

function create(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}

查找字符串中出现最多的字符和个数
: abbcccddddd -> 字符最多的是d,出现了5let str = "abcabcabcbbccccc";
let num = 0;
let char = '';

 // 使其按照一定的次序排列
str = str.split('').sort().join('');
// "aaabbbbbcccccccc"

// 定义正则表达式
let re = /(\w)\1+/g;
str.replace(re,($0,$1) => {
    if(num < $0.length){
        num = $0.length;
        char = $1;        
    }
});
console.log(`字符最多的是${char},出现了${num}`);
//数组去重
ES6方法(使用数据结构集合):
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]

一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了

function promiseAll(promises) {
  return new Promise(function(resolve, reject) {
    if(!Array.isArray(promises)){
        throw new TypeError(`argument must be a array`)
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedResult = [];
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(promises[i]).then(value=>{
        resolvedCounter++;
        resolvedResult[i] = value;
        if (resolvedCounter == promiseNum) {
            return resolve(resolvedResult)
          }
      },error=>{
        return reject(error)
      })
    }
  })
}
// test
let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
promiseAll([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
})

1. 实现一个数组去重的函数 思路:使用对象来存储数组中的元素,遍历数组,若元素在对象中不存在,则存储到对象中,并将其推入新数组中。 2. 实现一个函数,判断一个字符串是否是回文字符串 思路:将字符串翻转,与原字符串比较是否相等。 3. 实现一个函数,可以将多维数组转化为一维数组 思路:使用递归来遍历多维数组,将每个元素推入新数组中,直到遍历完所有元素。 4. 实现一个函数,统计一个字符串中出现次数最多的字符 思路:使用对象来存储每个字符出现的次数,遍历字符串,将每个字符存储到对象中,找到出现次数最多的字符。 5. 实现一个函数,实现数组的冒泡排序 思路:使用双重循环遍历数组,比较相邻两个元素的大小,如果前者大于后者,则交换两个元素的位置,直到遍历完数组。 6. 实现一个函数,实现数组的快速排序 思路:选择数组中的一个元素作为基准点,将数组分为两个部分,一部分大于基准点,一部分小于基准点,递归处理两个部分。 7. 实现一个函数,实现数组的深拷贝 思路:使用递归遍历数组中的每个元素,判断元素类型,如果是对象或数组,则进行深拷贝,如果是基本类型,则直接复制。 8. 实现一个函数,实现函数的柯里化 思路:使用闭包保存参数,当参数个数达到预设值时,执行函数。 9. 实现一个函数,实现函数的节流 思路:使用定时器来控制函数执行的频率,每次函数执行时,清除定时器并重新设置一个定时器。 10. 实现一个函数,实现函数的防抖 思路:使用定时器来延迟函数执行,每次函数执行时,清除定时器并重新设置一个定时器。如果在定时器延迟时间内再次触发函数,则重新计时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可爱的小红帽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值