常见js手撕题及算法总结

实现一下观察者模式
class Subject {
   
    constructor () {
   
        this.state = 0
        this.observe = []
    }
    getState () {
   
        return this.state
    }
    setState (val) {
   
        this.state = val
        this.observe.forEach((item) => {
   
            item.update()
        })
    }
    attach(ob) {
   
        this.observe.push(ob)
    }
}

class Observe {
   
    constructor (name, sub) {
   
        this.name = name
        this.sub = sub
        this.sub.attach(this)
    }
    update () {
   
        console.log(`${
     this.name} update, state: ${
     this.sub.getState()}`)
    }
}
实现一下工厂模式
// 工厂模式
class Role {
   
    constructor(options) {
   
        this.role = options.role;
        this.permissions = options.permissions;
    }
    show() {
   
        const str = `是一个${
     this.role}, 权限:${
     this.permissions.join(', ')}`;
        console.log(str);
    }
}

class SimpleFactory {
   
    constructor(role) {
   
        if(typeof this[role] !== 'function') {
   
            throw new Error('参数只能为 admin 或 developer');
        }
        return this[role]();
    }

    admin() {
   
        return new Role({
   
            role: '管理员',
            permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论']
        });
    }
    developer() {
   
        return new Role({
   
            role: '开发者',
            permissions: ['开发', '推送', '提问', '评论']
        });
    }
}
实现一下单例模式
class LoginForm {
   
    constructor () {
   
        this.state = 'hide'
    }
    show () {
   
        if (this.state === 'show') {
   
            console.log('已经show')
        }
        this.state = 'show'
        console.log('登录框show成功')
    }
    hide () {
   
        if (this.state === 'hide') {
   
            console.log('已经hide')
        }
        this.state = 'hide'
        console.log('登录框hide成功')
    }
}

LoginForm.getInstance = (function () {
   
    let instance = null
    return function () {
   
        if (!instance) {
   
            instance = new LoginForm()
        }
        return instance
    }
})()
设计一个lazyMan,实现以下功能:

LazyMan(‘Tony’);
// Hi I am Tony

LazyMan(‘Tony’).sleep(10).eat(‘lunch’);
// Hi I am Tony
// 等待了10秒…
// I am eating lunch
LazyMan(‘Tony’).eat(‘lunch’).sleep(10).eat(‘dinner’);
// Hi I am Tony
// I am eating lunch
// 等待了10秒…
// I am eating diner
LazyMan(‘Tony’).eat(‘lunch’).eat(‘dinner’).sleepFirst(5).sleep(10).eat(‘junk food’);
// Hi I am Tony
// 等待了5秒…
// I am eating lunch
// I am eating dinner
// 等待了10秒…
// I am eating junk food

考察点:运用发布订阅者模式,js事件执行机制

function lazyMan(name) {
   
    // 任务清单队列
    this.taskList = []
    this.name = name
    console.log(`Hi I am ${
     name}`)
    setTimeout(() => this.next())
}
lazyMan.prototype = {
   
    // 订阅方法
    eat (food) {
   
        const fn = () => {
   
            console.log(`i am eating ${
     food}`);
            this.next()
        }
        this.taskList.push(fn)
        return this
    },
    sleepFirst (time) {
   
        const fn = () => {
   
            setTimeout(() => {
   
                console.log(`等待了${
     time}`);
                this.next()
            }, time*1000)
        }
        this.taskList.unshift(fn)
        return this
    },
    sleep (time) {
   
        const fn = () => {
   
            setTimeout(() => {
   
                console.log(`等待了${
     time}`);
                this.next()
            }, time*1000)
        }
        this.taskList.push(fn)
        return this
    },
    // 事件发布
    next () {
   
        const fn = this.taskList.shift()
        fn && fn()
    }
}
function LazyMan (name) {
   
    return new lazyMan(name)
}

LazyMan('Tony')
LazyMan('Tony').sleep(10).eat('lunch')
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner')
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')
实现一个简单的EventEmitter

就是事件的触发机制,发布订阅者的一个实现,和上题思路一样

function eventEmitter () {
   
	// 定义事件池
    this.eventpool = {
   }
    // 事件绑定
    this.on = function (event, callback) {
   
        this.eventpool[event] ? this.eventpool[event].push(callback) : this.eventpool[event]
    }
    // 事件分发
    this.emit = function (event, ...args) {
   
        this.eventpool[event] && this.eventpool[event].forEach((cb) => cb(...args))
    }
    // 事件解绑
    this.off (event) {
   
        if (this.eventpool[event]) {
   
            delete this.eventpool[event]
        }
    }
    // 事件只绑定执行一次
    this.once(event, callback) {
   
        this.on(event, (...args) => {
   
            callback(...args)
            this.off(event)
        })
    }
}

考察点:事件触发与事件监听器功能的封装

以上两个手撕题涉及的
发布 + 订阅
DOM 的事件机制就是发布订阅模式最常见的实现,这大概是前端最常用的编程模型了,监听某事件,当该事件发生时,监听该事件的监听函数被调用。
————————————————————————————————————
发布订阅模式,阮一峰在《Javascript 异步编程的 4 种方法》,中:

我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe
pattern),又称"观察者模式"(observer pattern)。

手撕实现原生js的一些方法(call、apply、bind、map、reduce、filter、splice、pop、push、unshift、shift)
  • 实现call方法
// call的实现(实现call)
Function.prototype.call = function (context) {
   
  context = context ? Object(context) : window
  context.fn = this
  let args = [...arguments].slice(1)
  let res = context.fn(...args)
  delete context.fn
  return res
}
  • 实现apply方法
// apply的实现
Function.prototype.apply = function (context, arr) {
   
  context = context ? Object(context) : window
  context.fn = this
  let res
  if (!arr) {
   
    res = context.fn()
  } else {
   
    res = context.fn(...arr)
  }
  delete context.fn
  return res
}
  • 实现bind方法
// 函数实现
function bind(fn, context) {
   
    let args = Array.prototype.slice.call(arguments, 2)
    return function () {
   
        return fn.apply(context, args.concat(Array.prototype.slice.call(arguments)))
    }
}
// 原型链修改
Function.prototype.bind = function (context) {
   
    let that = this
    let args = Array.prototype.slice.call(arguments, 1)
    return function () {
   
        return that.apply(context, args.concat(Array.prototype.slice.call(arguments)))
    }
}

// 更为完整的方法
Function.prototype.bind2 = function (context) {
   

    if (typeof this !== "function") {
   
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {
   };

    var fBound = function () 
  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值