2021年前端高频面试题精选(上)

65 篇文章 2 订阅
10 篇文章 0 订阅
本文汇总了前端面试中常见的几道题目,包括手写观察者模式、EventEmitter实现、事件侦听器、sleep函数、Object.assign、instanceof的实现、防抖和节流函数以及深拷贝。通过这些练习,帮助开发者熟悉和掌握前端开发中的关键概念和技术。
摘要由CSDN通过智能技术生成

知己知彼,百战百胜。面试也是如此,想要拿到大厂offer,首先我们要摸清他们面试的套路,今天小知了就准备了十道前端必备的高频面试题,希望对大家有所帮助~
在这里插入图片描述

1、手写一个观察者模式

class Subject{
constructor(name){
this.name = name
this.observers = []
this.state = ‘XXXX’
}
// 被观察者要提供一个接受观察者的方法
attach(observer){
this.observers.push(observer)
}

// 改变被观察着的状态
setState(newState){
this.state = newState
this.observers.forEach(o=>{
o.update(newState)
})
}
}

class Observer{
constructor(name){
this.name = name
}

update(newState){
console.log(${this.name}say:${newState})
}
}

// 被观察者 灯
let sub = new Subject(‘灯’)
let mm = new Observer(‘小明’)
let jj = new Observer(‘小健’)

// 订阅 观察者
sub.attach(mm)
sub.attach(jj)

sub.setState(‘灯亮了来电了’)
2.EventEmitter 实现

class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
let callbacks = this.events[event] || [];
callbacks.push(callback);
this.events[event] = callbacks;
return this;
}
off(event, callback) {
let callbacks = this.events[event];
this.events[event] = callbacks && callbacks.filter(fn => fn !== callback);
return this;
}
emit(event, …args) {
let callbacks = this.events[event];
callbacks.forEach(fn => {
fn(…args);
});
return this;
}
once(event, callback) {
let wrapFun = function (…args) {
callback(…args);
this.off(event, wrapFun);
};
this.on(event, wrapFun);
return this;
}
}
3.写一个通用的事件侦听器函数。

const EventUtils = {
// 视能力分别使用dom0||dom2||IE方式 来绑定事件
// 添加事件
addEvent: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent(“on” + type, handler);
} else {
element[“on” + type] = handler;
}
},
// 移除事件
removeEvent: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent(“on” + type, handler);
} else {
element[“on” + type] = null;
}
},
// 获取事件目标
getTarget: function(event) {
return event.target || event.srcElement;
},
// 获取 event 对象的引用,取到事件的所有信息,确保随时能使用 event
getEvent: function(event) {
return event || window.event;
},
// 阻止事件(主要是事件冒泡,因为 IE 不支持事件捕获)
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
// 取消事件的默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
};
4.怎么实现一个sleep
sleep函数作用是让线程休眠,等到指定时间在重新唤起。
function sleep(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue;
}
}

function test() {
console.log(‘111’);
sleep(2000);
console.log(‘222’);
}

test()
5.实现 Object.assign

Object.assign2 = function(target, …source) {
if (target == null) {
throw new TypeError(‘Cannot convert undefined or null to object’)
}
let ret = Object(target)
source.forEach(function(obj) {
if (obj != null) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
ret[key] = obj[key]
}
}
}
})
return ret
}
6.instanceof的实现
instanceof 是用来判断A是否为B的实例,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
不能检测基本数据类型,在原型链上的结果未必准确,不能检测null,undefined
实现:遍历左边变量的原型链,直到找到右边变量的 prototype,如果没有找到,返回 false
function myInstanceOf(a,b){
let left = a.proto;
let right = b.prototype;
while(true){
if(left == null){
return false
}
if(left == right){
return true
}
left = left.proto
}
}

//instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left), // 获取对象的原型
prototype = right.prototype; // 获取构造函数的 prototype 对象
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
7.实现防抖函数(debounce)
连续触发在最后一次执行方法,场景:输入框匹配
let debounce = (fn,time = 1000) => {
let timeLock = null

return function (...args){
    clearTimeout(timeLock)
    timeLock = setTimeout(()=>{
        fn(...args)
    },time)
}

}
8.实现节流函数(throttle)
在一定时间内只触发一次,场景:长列表滚动节流
let throttle = (fn,time = 1000) => {
let flag = true;

return function (...args){
    if(flag){
        flag = false;
        setTimeout(()=>{
            flag = true;
            fn(...args)
        },time)
    }
}

}
9.深拷贝(deepclone)
判断类型,正则和日期直接返回新对象
空或者非对象类型,直接返回原值
考虑循环引用,判断如果hash中含有直接返回hash中的值
新建一个相应的new obj.constructor加入hash
遍历对象递归(普通key和key是symbol情况)
function deepClone(obj,hash = new WeakMap()){
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeof obj !== ‘object’) return obj;
//循环引用的情况
if(hash.has(obj)){
return hash.get(obj)
}
//new 一个相应的对象
//obj为Array,相当于new Array()
//obj为Object,相当于new Object()
let constr = new obj.constructor();
hash.set(obj,constr);
for(let key in obj){
if(obj.hasOwnProperty(key)){
constr[key] = deepClone(obj[key],hash)
}
}
//考虑symbol的情况
let symbolObj = Object.getOwnPropertySymbols(obj)
for(let i=0;i<symbolObj.length;i++){
if(obj.hasOwnProperty(symbolObj[i])){
constr[symbolObj[i]] = deepClone(obj[symbolObj[i]],hash)
}
}
return constr
}
10.ES6继承

//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People{
constructor(name=‘wang’,age=‘27’){
this.name = name;
this.age = age;
}
eat(){
console.log(${this.name} ${this.age} eat food)
}
}
//继承父类
class Woman extends People{
constructor(name = ‘ren’,age = ‘27’){
//继承父类属性
super(name, age);
}
eat(){
//继承父类方法
super.eat()
}
}
let wonmanObj=new Woman(‘xiaoxiami’);
wonmanObj.eat();

//es5继承先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。
//es6继承是使用关键字super先创建父类的实例对象this,最后在子类class中修改this。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值