Git Product home page Git Product logo

Comments (19)

574495412 avatar 574495412 commented on May 18, 2024 17

function deepclone(){
type of (obj)!='object ‘ || obj==null
}

from fe-interview.

zyronon avatar zyronon commented on May 18, 2024 10
class Observer {
        static events = new Map()

        static on(name, fn) {
            this.events.set(name, {isOnce: false, fn})
        }

        static once(name, fn) {
            this.events.set(name, {isOnce: true, fn})
        }

        static off(name) {
            this.events.delete(name)
        }

        static emit(name, data) {
            let cache = this.events.get(name)
            if (cache) {
                if (cache.isOnce) this.events.delete(name)
                cache.fn(data)
            }
        }
    }

from fe-interview.

syou-yu avatar syou-yu commented on May 18, 2024 2
class EventBus {
  listeners = [];

  on(name, fn) {
    const listener = {
      name,
      fn,
      isOnce: false,
    };
    this.listeners.push(listener);
    return listener;
  }

  once(name, fn) {
    const listener = {
      name,
      fn,
      isOnce: true,
    };
    this.listeners.push(listener);
    return listener;
  }

  off(listener) {
    const index = this.listeners.findIndex(lst => lst === listener);
    if (index > -1) {
      this.listeners.splice(index, 1);
    }
  }

  emit(name, data) {
    for (const listener of this.listeners) {
      if (listener.name === name) {
        try {
          if (listener.isOnce) this.off(listener);
          listener.fn(data);
        } catch (error) {
          console.error('bus emit error', error);
        }
      }
    }
  }
}

const test = new EventBus();

const test1 = test.on('console', () => console.log('123'));
const test2 = test.on('console', () => console.log('456'));
const test3 = test.once('console', () => console.log('789'));

// 第一次
test.emit('console', null);
// 123
// 456
// 789

// 第二次
test.emit('console', null);
// 123
// 456

// 第三次
test.off(test2);
test.emit('console', null);
// 123

from fe-interview.

qzruncode avatar qzruncode commented on May 18, 2024 1
熟写发布订阅模式可以锻炼你的增删改查能力
class PubSub {
  sid = 0
  topicList = {}
  constructor(...tops) {
    this.topicList = Object.fromEntries(tops.map(item => [item, []]));
  }
  isValidTopic(topic){
    return Object.keys(this.topicList).includes(topic)
  }
  sub(topic, target) {
    const isValidTopic = this.isValidTopic(topic);
    if(isValidTopic){
      target.id = ++this.sid;
      target[Symbol.for('update')] = function(cb) {
        cb();
      }
      this.topicList[topic].push(target);
    }
  }
  pub(topic, cb) {
    const isValidTopic = this.isValidTopic(topic);
    if(isValidTopic){
      this.topicList[topic].forEach(o => {
        o[Symbol.for('update')](cb);
      })
    }
  }
  unsub(topic, target) {
    const isValidTopic = this.isValidTopic(topic);
    if(isValidTopic){
      const i = this.topicList[topic].findIndex(o => o.id == target.id);
      if(i != -1) {
        this.topicList[topic].splice(i, 1);
      }
    }
  }
}

const pb = new PubSub('china', 'america');
const o1 = {};
const o2 = {};
pb.sub('china', o1);
pb.sub('america', o2);

pb.pub('america', () => {
  console.log('对你实施制裁!!!');
})
pb.pub('china', () => {
  console.log('强烈反对!!!');
})

pb.unsub('china', o1);
pb.unsub('america', o2);

console.log(pb.topicList);

from fe-interview.

Charles-ShiZ avatar Charles-ShiZ commented on May 18, 2024 1
class EventEmitter {
  constructor(){
    this.events = {}
  }
  on(eventName, callback){
    const callbacks = this.events[eventName]
    if( callbacks ){
      callbacks.add(callback)
    } else {
      this.events[eventName] = new Set([callback])
    }
    return this.events
  }
  once(eventName, callback){
    const onceCallback = (...args)=>{
      callback(...args)
      this.off(eventName, onceCallback)
    }
    this.on(eventName, onceCallback)
    return this.events
  }
  emit(eventName){
    this.events[eventName] && this.events[eventName].forEach(f=>f());
    return this.events
  }
  off(eventName, callback){
    this.events[eventName] && this.events[eventName].delete(callback)
    return this.events
  }
}

from fe-interview.

Genzhen avatar Genzhen commented on May 18, 2024
// 发布订阅中心, on-订阅, off取消订阅, emit发布, 内部需要一个单独事件中心caches进行存储;

interface CacheProps {
  [key: string]: Array<((data?: unknown) => void)>;
}

class Observer {

  private caches: CacheProps = {}; // 事件中心

  on (eventName: string, fn: (data?: unknown) => void){ // eventName事件名-独一无二, fn订阅后执行的自定义行为
    this.caches[eventName] = this.caches[eventName] || [];
    this.caches[eventName].push(fn);
  }

  emit (eventName: string, data?: unknown) { // 发布 => 将订阅的事件进行统一执行
    if (this.caches[eventName]) {
      this.caches[eventName].forEach((fn: (data?: unknown) => void) => fn(data));
    }
  }

  off (eventName: string, fn?: (data?: unknown) => void) { // 取消订阅 => 若fn不传, 直接取消该事件所有订阅信息
    if (this.caches[eventName]) {
      const newCaches = fn ? this.caches[eventName].filter(e => e !== fn) : [];
      this.caches[eventName] = newCaches;
    }
  }
  
}

from fe-interview.

Genzhen avatar Genzhen commented on May 18, 2024
class EventListener {
    listeners = {};
    on(name, fn) {
        (this.listeners[name] || (this.listeners[name] = [])).push(fn)
    }
    once(name, fn) {
        let tem = (...args) => {
            this.removeListener(name, fn)
            fn(...args)
        }
        fn.fn = tem
        this.on(name, tem)
    }
    removeListener(name, fn) {
        if (this.listeners[name]) {
            this.listeners[name] = this.listeners[name].filter(listener => (listener != fn && listener != fn.fn))
        }
    }
    removeAllListeners(name) {
        if (name && this.listeners[name]) delete this.listeners[name]
        this.listeners = {}
    }
    emit(name, ...args) {
        if (this.listeners[name]) {
            this.listeners[name].forEach(fn => fn.call(this, ...args))
        }
    }
}

from fe-interview.

523451928 avatar 523451928 commented on May 18, 2024
function Events() {
  this.eventHub = {}
}

Events.prototype.$on = function(eventName, fn) {
  this.eventHub[eventName] = (this.eventHub[eventName] || []).concat(fn)
}

Events.prototype.$emit = function(eventName, args) {
  if (this.eventHub[eventName]) {
    this.eventHub[eventName].forEach((fn) => {
      fn(args)
    })
  }
}

Events.prototype.$off = function(eventName, fn) {
  if (this.eventHub[eventName]) {
    if (!fn) {
      this.eventHub[eventName] = []
    } else {
      this.eventHub[eventName] = this.eventHub[eventName].filter(fun => fun !== fn)
    }
  }
}

Events.prototype.$once = function(eventName, fn) {
  const fun = (...args) => {
    fn.apply(this, args)
    this.$off(eventName, fn)
  }
  this.$on(eventName, fun)
}
function test(a) {
  console.log(a)
}
var event = new Events()
event.$once('test', test)
event.$emit('test', 1)

from fe-interview.

GolderBrother avatar GolderBrother commented on May 18, 2024
class EventEmitter {
    constructor(){
        this.events = {};
    }
    on(event, callback){
        const callbacks = this.events[event] || [];
        if(Array.isArray(callbacks)) {
            callbacks.push(callback);
            this.events[event] = callbacks;
        }
        return this;
    }
    off(event, callback){
        const callbacks = (this.events[event] || []).filter(cb => cb !== callback);
        this.events[event] = callbacks;
        return this;
    }
    once(event, callback){
        const wrap = (...args) => {
            typeof callback === 'function' && callback.apply(this, args);;
            this.off(event, wrap);
        }
        this.on(event, wrap);
        return this;
    }
    emit(event) {
        const callbacks = this.events[event] || [];
        if(Array.isArray(callbacks)) {
            callbacks.forEach(cb => typeof cb === 'function' && cb());
        }
        return this;
    }
}

const eventEmitter = new EventEmitter();
eventEmitter.on('click', () => {
    console.log('click 1')
})
eventEmitter.on('click', () => {
    console.log('click 2')
})

// eventEmitter.off('click')
eventEmitter.emit('click')
eventEmitter.once('click')
console.log(eventEmitter);

click 1
click 2
EventEmitter {
  events: { click: [ [Function], [Function], [Function: wrap] ] } }

from fe-interview.

Luoyuda avatar Luoyuda commented on May 18, 2024
function EventEmitter(){
    this.caches = {}
}
EventEmitter.prototype.on = function(type, event){
    if(!this.caches[type]) this.caches[type] = []
    this.caches[type].push(event)
    return this
}
EventEmitter.prototype.off = function(type, event){
    if(!this.caches[type]) return
    this.caches[type] = this.caches[type].filter(item => item !== event)
    return this
}
EventEmitter.prototype.once = function(type, event){
    var _event = function(){
        event.apply(this, arguments)
        this.off(type, _event)
    }
    this.on(type, _event)
    return this
}
EventEmitter.prototype.emit = function(){
    var type = arguments[0]
    if(!this.caches[type]) return
    var args = Array.prototype.slice.call(arguments, 1)
    for(let event of this.caches[type]){
        event.apply(this, args)
    }
    return this
}
// 使用如下
var e = new EventEmitter();
e.on('log', console.log)
e.on('log', console.log)
e.emit('log', 1, 2, 3, 4)
e.emit('log', 1, 2, 3, 4)
e.off('log', console.log)
e.emit('log', 1, 2, 3, 4)
e.once('log', console.log)
e.emit('log', 1, 2, 3, 4)
e.emit('log', 1, 2, 3, 4)

from fe-interview.

wjiantao avatar wjiantao commented on May 18, 2024
//菜鸟一枚,如有出错请多指教
class EventEmitter {
  constructor() {
    this.events = {};
  }
  on(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [callback];
    } else {
      this.events[eventName].push(callback);
    }
  }
  emit(eventName) {
    this.events[eventName] && this.events[eventName].forEach((cb) => cb());
  }
}

var e = new EventEmitter();

function workDay() {
  console.log("每天工作");
}
function makeMoney() {
  console.log("赚100万");
}
function sayLove() {
  console.log("向喜欢的人示爱");
}

e.on("money", makeMoney);
e.on("work", workDay);
e.on("love", sayLove);

e.emit("money");
e.emit("work");
e.emit("love");

from fe-interview.

safarishi avatar safarishi commented on May 18, 2024
class Observer {
        static events = new Map()

        static on(name, fn) {
            this.events.set(name, {isOnce: false, fn})
        }

        static once(name, fn) {
            this.events.set(name, {isOnce: true, fn})
        }

        static off(name) {
            this.events.delete(name)
        }

        static emit(name, data) {
            let cache = this.events.get(name)
            if (cache) {
                if (cache.isOnce) this.events.delete(name)
                cache.fn(data)
            }
        }
    }

这里对于监听多次的情况是否未处理

from fe-interview.

zizxzy avatar zizxzy commented on May 18, 2024

订阅和发布的关键在利用一个对象或者map存储事件对象,on是添加事件,off是删除事件,emit是遍历事件对象然后调用

class EventEmitter {
  constructor() {
    this.event = {};
  }

  on(eventName, callbackFunc) {
    const callback = this.event[eventName] || [];
    if (Array.isArray(callback)) {
      callback.push(callbackFunc);
      this.event[eventName] = callback;
    }
    return this.event;
  }

  off(eventName, callback) {
    if (this.event[eventName]) {
      const newEventCallback = this.event[eventName].filter(c => c !== callback);
      this.event[eventName] = newEventCallback;
    }
    return this.event;
  }

  emit(eventName, data) {
    if (this.event[eventName]) {
      this.event[eventName].forEach(callback => {
        callback && callback(data);
      });
    }
    return this.event;
  }
}

const eventEmitter = new EventEmitter();
const clickFunc = function () {
  console.log('click 1');
}
eventEmitter.on('click', clickFunc)
eventEmitter.on('click', () => {
  console.log('click 2')
})
eventEmitter.emit('click')
eventEmitter.off('click', clickFunc);
eventEmitter.emit('click')

from fe-interview.

SnailOwO avatar SnailOwO commented on May 18, 2024
class eventEmitter {
        list = {}

        on(event, fn) {
            (this.list[event] || (this.list[event] = [])).push(fn)
            return this
        }

        off(event, fn) {
            const curFns = this.list[event] || []
            if (!curFns.length) {
                return false
            }
            for (const key of Object.keys(curFns)) {
                const val = curFns[key]
                if (val === fn || val.fn === fn) {
                    curFns.splice(key, 1)
                    break
                }
            }
            return this
        }

        once(event, fn) {
            const on = () => {
                fn.apply(this, arguments)
                this.off(event, on)
            }
            this.on(event, on)
            return this
        }

        emit() {
            const curEvent = Array.prototype.shift.apply(arguments)
            const curFns = this.list[curEvent]
            if (!curFns.length) {
                return false
            }
            for (const val of curFns) {
                val.apply(this, arguments)
            }
        }
    }
   const eventEmit = new eventEmitter()
   eventEmit.on('article1', user3).emit('article1', 'test111');
   function user3(content) {
        console.log('用户3订阅了:', content);
    }

from fe-interview.

18602435705 avatar 18602435705 commented on May 18, 2024
class EventListener {
  constructor() {
    this.events = {};
  }
  on(e, cb) {
    const { events } = this;
    (events[e] || (events[e] = [])).push(cb);
  }

  once(e, cb) {
    const once = (...args) => {
      cb(...args);
      this.off(e, once);
    };
    once.fn = cb;
    this.on(e, once);
  }

  off(e, cb) {
    const cbs = this.events[e] || [];
    let item;
    let i = cbs.length;
    while (i--) {
      item = cbs[i];
      // 兼容移除once事件
      if (cb === item || cb === item.fn) {
        cbs.splice(i, 1);
        break;
      }
    }
  }

  emit(e, ...args) {
    const { events } = this;
    (events[e] || []).forEach((cb) => cb(...args));
  }
}

// 测试
const eventer = new EventListener();
const f1 = () => console.log(111);
const f2 = () => console.log(222);
eventer.on("click", f1);
eventer.once("click", f2);
eventer.off("click", f2);
eventer.emit("click");

from fe-interview.

syou-yu avatar syou-yu commented on May 18, 2024

from fe-interview.

wringY avatar wringY commented on May 18, 2024
class Observer {
    constructor() {
        this.eventsMap = {}
    }

    on(type, callback) {
        if (!this.eventsMap[type]) {
            this.eventsMap[type] = []
        }
        this.eventsMap[type].push({once: false, callback})
    }
    once(type, callback) {
        if (!this.eventsMap[type]) {
            this.eventsMap[type] = []
        }
        this.eventsMap[type].push({once: true, callback})
    }
    emit(type, payload) {
        let queue = this.eventsMap[type]
        let index = 0;
        while (index < queue.length && queue) {
            const depObj = [...queue].shift()
            if (depObj.once) {
                depObj.callback(payload)
                queue.splice(index, 1)
            } else {
                depObj.callback(payload)
            }
            index++
        }
    }
}

const ev = new Observer()
ev.on('change', function(res) {
    console.log(res)
})

// ev.emit('change', 10)
// ev.emit('change', 10)
// ev.emit('change', 10)

ev.once('input', function(res) {
    console.log(res)
})
ev.emit('input', 20)
ev.emit('input', 20)
ev.emit('input', 20)

from fe-interview.

Kisthanny avatar Kisthanny commented on May 18, 2024
/**
 * 手写发布订阅
 * 比如vue的自定义事件
 * 父组件 v-on:('update',(e)=>{console.log(e)})
 * 子组件 $emit('update', {data:1})
 *
 * 发布订阅是一个类
 * 一般有4个方法
 * $on: 入参为一个事件名,一个回调函数
 * $emit: 入参为一个事件名,一个传给回调函数的数据
 * $once: 与$on类似,但是触发一次回调后就被销毁
 * $off: 入参为一个事件名,一个对应的$on注册时的回调function
 */

class EventEmitter {
  constructor() {
    this.eventHub = {};
  }
  $on(name, fn) {
    if (!this.eventHub[name]) {
      this.eventHub[name] = [];
    }
    this.eventHub[name].push(fn);
  }
  $emit(name, ...data) {
    if (this.eventHub[name]) {
      this.eventHub[name].forEach((fn) => {
        fn(...data);
      });
    }
  }
  $off(name, fn) {
    if (!this.eventHub[name]) {
      return;
    }
    if (fn === undefined) {
      this.eventHub[name] = [];
    } else {
      this.eventHub[name] = this.eventHub[name].filter((cb) => cb !== fn);
    }
  }
  $once(name, fn) {
    const wrap = (...args) => {
      this.$off(name, wrap);
      fn(...args);
    };
    this.$on(name, wrap);
  }
}

from fe-interview.

syou-yu avatar syou-yu commented on May 18, 2024

from fe-interview.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.