手写题汇总 js当中有什么手写题呢?
哈喽哈喽,我是你们的金樽清酒。最近面字节和百度都失败了。并不是说八股背的不够多,而是基础不够扎实。字节让我明白算法基础不够,百度面试更让我打开了新世界的大门。百度没有问我八股,而是问我项目协作,和专业基础。所以,背八股想进大厂是不可能的,更重要的是会解决问题,代码的基础足够的牢固。那今天让我们js基础,一些常见的手写题梳理一下吧。
一.发布订阅
发布订阅这种设计模式是特别常见的。让我们简单的手写一下里面的四种方法。on,off,once,emit。
这四种方法分别有什么功能呢?
on:订阅,把事件和方法存起来
off:把事件里面的方法删除
once:一个事件只存一个方法
emit:将事件里面的方法全部都触发掉。
- 先写on方法吧
class EventEmiter {
constructor() {
this.handels = {}//用一个对象来存订阅的事件
}
on(eventName, cb) {//在构造函数的原型上面,让实例对象隐式继承
if (!this.handels[eventName]) {
this.handels[eventName] = []
}
this.handels[eventName].push(cb)
}//这个就是on方法,收集订阅的内容,将所有的依赖进行收集。
}
先在构造函数上面放一个对象来存订阅的事件。
然后on方法接受两个参数,一个事件名,一个方法回调。如果这个事件不存在,给这个事件赋为空数组,再把后面的回调存进去。这就是on方法了。
可以看到handles对象上就出现了sell事件。
- on方法
class EventEmiter {
constructor() {
this.handels = {}//用一个对象来存订阅的事件
}
on(eventName, cb) {//在构造函数的原型上面,让实例对象隐式继承
if (!this.handels[eventName]) {
this.handels[eventName] = []
}
this.handels[eventName].push(cb)
}//这个就是on方法,收集订阅的内容,将所有的依赖进行收集。
}
off(eventName, cb) {//取消订阅
if (this.handels[eventName]) {
const handels = this.handels[eventName]
const index = handels.indexOf(cb)
if (index !== -1) {
handels.splice(index, 1)
}
}
}
off方法也需要两个参数,它会找到该事件对应的某个方法,所以我们获取那个方法的下标,然后用splice修改。一定得事件这个数组是否存在,不然会报错,不是数组用不了数组上的方法。
可以看到,我们on订阅了一个方法,off取消了订阅,该事件数组为空。
- once方法
once方法是一个事件只能订阅一次,那这个也很好写,那就判断数组是否为空,为空调用on方法,否则直接返回。
class EventEmiter {
constructor() {
this.handels = {}//用一个对象来存订阅的事件
}
on(eventName, cb) {//在构造函数的原型上面,让实例对象隐式继承
if (!this.handels[eventName]) {
this.handels[eventName] = []
}
this.handels[eventName].push(cb)
}//这个就是on方法,收集订阅的内容,将所有的依赖进行收集。
}
off(eventName, cb) {//取消订阅
if (this.handels[eventName]) {
const handels = this.handels[eventName]
const index = handels.indexOf(cb)
if (index !== -1) {
handels.splice(index, 1)
}
}
}
once(eventName, cb) {
const handels = this.handels[eventName]
if (!handels) {
this.on(eventName, cb)
}
return
}
可以看到,当once两个方法后,数组里面只存第一个。
- emit,发布事件,实际上就是触发事件里面存的所有方法。
class EventEmiter {
constructor() {
this.handels = {}//用一个对象来存订阅的事件
}
on(eventName, cb) {//在构造函数的原型上面,让实例对象隐式继承
if (!this.handels[eventName]) {
this.handels[eventName] = []
}
this.handels[eventName].push(cb)
}//这个就是on方法,收集订阅的内容,将所有的依赖进行收集。
}
off(eventName, cb) {//取消订阅
if (this.handels[eventName]) {
const handels = this.handels[eventName]
const index = handels.indexOf(cb)
if (index !== -1) {
handels.splice(index, 1)
}
}
}
once(eventName, cb) {
const handels = this.handels[eventName]
if (!handels) {
this.on(eventName, cb)
}
return
}
emit(eventName) {//将事件发布,触发所有的依赖
if (this.handels[eventName]) {
const handles = this.handels[eventName]
handles.forEach(cb => {
cb()
})
}
}
如果事件数组存在,就遍历这个数组,全部调用里面的函数。
这样我们的发布订阅就写完了。
单例模式
什么是单例模式呢?通俗来说就是不管new 多少遍都是得到同一个实例对象。就像vuex就是一个单例模式。它是一个全局的状态管理,那么肯定不管new多少次都是在同一个实例对象,操作同一个对象。来来来,让我们一起实现一个简单的单例模式。
- 方法一 用构造函数的静态属性
class Person {
constructor(name) {
this.name = name
}
static getInfo(name) {
if (!Person.instance) {
Person.instance = new Person(this.name)
}
return Person.instance
}
}
let p1 = Person.getInfo('li')
let p2 = Person.getInfo('li')
console.log(p1 === p2);//true
在构造函数的静态上面写一个方法,在构造函数上面挂一个instance属性,属性值就是new的实例对象,如果该字段存在则直接返回。这样就是靠对象上的static静态方法实现单例模式。
- 方法二
const help = (function () {
let instance = null
return function () {
if (!instance) {
instance = new Storage()
}
return instance
}
})()
let p1 = new help()
let p2 = new help()
console.log(p1 === p2);//true
用一个辅助函数,同上的方法完成单例
最后打印的结果为true,我们就成功啦。这就是实现简单的单例模式。
结语
不要太着急赶路,而是感受路上的风景,各花各有各花香。既然学编程就要好好的一步步来,把编程基础学好,而不是人云亦云。
原文链接:https://juejin.cn/post/7355208166249005066 作者:jinzunqinjiu