Comments (19)
function deepclone(){
type of (obj)!='object ‘ || obj==null
}
from fe-interview.
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.
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.
熟写发布订阅模式可以锻炼你的增删改查能力
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.
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.
// 发布订阅中心, 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.
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.
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.
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.
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.
//菜鸟一枚,如有出错请多指教
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.
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.
订阅和发布的关键在利用一个对象或者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.
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.
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.
from fe-interview.
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.
/**
* 手写发布订阅
* 比如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.
from fe-interview.
Related Issues (20)
- Day378:说一下什么是 Http 协议无状态?怎么解决 Http 协议无状态?
- Day379:如果让你来实现一个前端监控系统,应该考虑什么?如何去实现?
- Day380:实现一个系统,统计前端页面性能、页面 JS 报错、用户操作行为、PV/UV、用户设备等消息,并进行必要的监控报警。方案如何设计,用什么技术点,什么样的系统架构,难点会在哪里? HOT 3
- Day381:说一下 JavaScript 严格模式下有哪些不同?
- Day382:说一下 setTimeout 和 setInterval 的区别,包含内存方面的分析?
- Day383:说下 React 的 useEffect、useCallback、useMemo HOT 2
- Day384:JavaScript 中如何实现一个类?怎么实例化这个类? HOT 2
- Day385:在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次?先执行冒泡还是捕获? HOT 9
- Day386:写一个通用的事件侦听器函数 HOT 3
- 定时函数 HOT 1
- 小程序不维护了吗? HOT 10
- --
- 小程序里面的内容还有其他地方能学习吗
- 求小程序哇!!不然学习效率太低了 HOT 1
- 现在还能在哪里看题目答案吗?小程序关闭了😭😭 HOT 1
- #### 1)为什么会有Event Loop
- > > > @Genzhen 请教一下大佬,如果在render里面结构赋值也会影响性能吗?比如 const { page, size } = this.state这种的? HOT 1
- 考察原型链
- issue路径错误,提不了pr,可见下图
- vue中&nextTick的原理
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fe-interview.