面向对象实现

3/14/2022 programming

# 组合式继承

function inherit(Child, Parent) {
    // 继承原型上的属性
    Child.prototype = Parent.prototype
    // 修复constructor
    Child.prototype.constructor = Child
    // 存储超类
    Child.super = Parent
    // 静态属性继承
    if (Object.setPrototypeOf) {
        Object.setPrototypeOf(Child, Parent)
    } else if (Child.__proto__) {
        Child.__proto__ = Parent
    } else {
        for (var k in Parent) {
            if (Parent.hasOwnProperty(k) && !(k in Child)) {
                Child[k] = Parent[k]
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 变形题

# 1. 设计LazyMan类

要求实现以下功能

LazyMan('Tony'); 
// Hi I am Tony 
LazyMan('Tony').sleep(10).eat('lunch'); 
// Hi I am Tony
// 等待了 10 秒...
// I am eating 
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了 10 秒...
// I am eating
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(1 0).eat('junk food');
// Hi I am Tony
// 等待了 5 秒...
// I am eating lunch
// I am eating dinner
// 等待了 10 秒...
// I am eating junk food
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
查看答案
  1. 定义一个类,里面要有事件队列,存储的是函数
  2. 每次执行完,要执行下一个函数next
  3. 每一个要返回this可以链式调用
  4. 最后封装一个函数,返回实例
class LazyManClass {
    constructor(name) {
        this.name = name
        this.queue = []
        console.log(`Hi I am ${name}`)
        setTimeout(() => {
            this.next()
        },0)
    }
    sleepFirst(time) {
        const fn = () => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`)
                this.next()
            }, time * 1000)
        }
        this.queue.unshift(fn)
        return this
    }
    sleep(time) {
        const fn = () => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`)
                this.next()
            },time * 1000)
        }
        this.queue.push(fn)
        return this
    }
    eat(food) {
        const fn = () => {
            console.log(`I am eating ${food}`)
            this.next()
        }
        this.queue.push(fn)
        return this
    }
    next() {
        const fn = this.queue.shift()
        fn && fn()
    }
}
function LazyMan(name) {
    return new LazyManClass(name)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 2. 实现一个Events模块

实现自定义事件的订阅、触发、移除功能。

const fn1 = (... args)=>console.log('I want sleep1', ... args)
const fn2 = (... args)=>console.log('I want sleep2', ... args)
const event = new Events();
event.on('sleep', fn1, 1, 2, 3);
event.on('sleep', fn2, 1, 2, 3);
event.fire('sleep', 4, 5, 6);
// I want sleep1 1 2 3 4 5 6
// I want sleep2 1 2 3 4 5 6
event.off('sleep', fn1);
event.once('sleep', () => console.log('I want sleep'));
event.fire('sleep');
// I want sleep2 1 2 3
// I want sleep
event.fire('sleep');
// I want sleep2 1 2 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
查看答案
  • 使用map当做key和value的查找
  • 每一个事件的内容也是一个map
  • 如果只有一次需要进行解绑
class Events {
  constructor() {
    this.events = new Map();
  }

  addEvent(key, fn, isOnce, ...args) {
    const value = this.events.get(key) ? this.events.get(key) : this.events.set(key, new Map()).get(key)
    value.set(fn, (...args1) => {
        fn(...args, ...args1)
        isOnce && this.off(key, fn)
    })
  }

  on(key, fn, ...args) {
    if (!fn) {
      console.error(`没有传入回调函数`);
      return
    }
    this.addEvent(key, fn, false, ...args)
  }

  fire(key, ...args) {
    if (!this.events.get(key)) {
      console.warn(`没有 ${key} 事件`);
      return;
    }
    for (let [, cb] of this.events.get(key).entries()) {
      cb(...args);
    }
  }

  off(key, fn) {
    if (this.events.get(key)) {
      this.events.get(key).delete(fn);
    }
  }

  once(key, fn, ...args) {
    this.addEvent(key, fn, true, ...args)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
更新时间: 2022-03-31 02:04