编程技术文章分享与教程

网站首页 > 技术文章 正文

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

hmc789 2024-11-18 12:56:44 技术文章 2 ℃

知己知彼,百战百胜。面试也是如此,想要拿到大厂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。

Tags:

标签列表
最新留言