es6入门观察者模式实现问题

在看es6入门的观察者模式实现时候(reflect章),运行报observable未定义

clipboard.png
这个是要引别的插件吗,还是哪里不对,书里也特别说明。
网上有很多观察者模式的实现,是要引用类似的模块吗

clipboard.png

为什么我这样走,就会报错

clipboard.png
我用webpack编译的

阅读 3.4k
3 个回答
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="text" >
<button onclick="test()">添加</button>
</body>
<script>
    const queuedObservers = new Set();
    const observe = fn => queuedObservers.add(fn);
    function set(target, key, value, receiver) {
        const result = Reflect.set(target, key, value, receiver);
        queuedObservers.forEach(observer => observer());
        return result;
    }
    const observable = obj => new Proxy(obj, {set});
    const person = observable({
        name: '张三',
        age: 20
    });

    
    function print() {
        document.querySelector("input").value = person.name;
        console.log(`${person.name}, ${person.age}`)
    }
    print();
    observe(print);
    function test(){
        person.name = '李四';

    }
</script>
</html>

你看下面不是用 set() 制作了一个 observable 么!

clipboard.png

所以你先把下面的代码运行一遍,然后就可以了.

您好,我写了一个易于理解的版本
因为前端这门语言太杂了,所以以后会陆续分别用ts、es5、es6去实现,先给您ts版本
观察者模式-ts版


/***
 * 抽象被观察者接口
 * 声明了添加、删除、通知观察者方法
 */
public interface Observerable {
    registerObserver(o:Observer);
    removeObserver(o:Observer):;
    notifyObserver();
}

/***
 * 抽象观察者
 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
 */
public interface Observer {
    update( message:string);
}



/**
 * 被观察者,也就是微信公众号服务
 * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
 */
public class WechatServer implements Observerable {
    private list:Observer[];
    private message:string;
    constructor(){
        this.list = [];
    }
    public registerObserver(o: Observer) {
        this.list.push(o)
    }
    public removeObserver(o: Observer) {
        for (var i=0; i < this.list.length; i++){
            if (this.list[i] === o){
                this.list.splice(i, 1);
                break;
            }
        }
    }
    public notifyObserver() {
        for(let i = 0; i < this.list.length; i++) {
            let oserver = this.list[i];
            oserver.update(this.message);
        }
    }
    public setInfomation(s:string) {
        this.message = s;
        console.log(`微信服务更新消息:${s}`);
        //消息更新,通知所有观察者
        this.notifyObserver();
    }
}


/**
 * 观察者
 */
public class User implements Observer {
    private  name:string;
    private  message:string;
    constructor(name:string) {
        this.name = name;
    }
    public update(message:string) {
        this.message = message;
        this.read();
    }
    public read() {
        console.log(`${this.name}收到推送消息:${this.message}`);
    }
}


/**
 * 我们来测试
 */
let server = new WechatServer();
let userZhang = new User("张三");
let userLi = new User("李四");
let userWang = new User("王五");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的语言!");
console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的语言!");



/**
 * 总结:这个是ts去写的,因为用js写,我觉得理解起来很费劲,哪怕是es2018!编译后可能就是你想要的版本吧
 * 这个模式是典型的观察者模式,而非变异后的发布-订阅模式,两者有关联,但是并不一样
 * 其实前边两个接口是可以不用定义的,但是接口就是用来做规范的,以后可能不只有微信服务,还有新闻订阅、小程序订阅、iphoneXR订购等等
 * 这个模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影像
 * 参考自java设计模式:https://www.cnblogs.com/luohanguo/p/7825656.html
 */

观察者模式-es5版
写完之后,突然发现,这尼玛不就是ts编译后的代码嘛,那两个抽象类的作用仅仅用在编译阶段,编译后的代码并不存在相关接口代码,哦!原来ts是这么个机制

/**
 * 被观察者,也就是微信公众号服务
 */
var WechatServer = (function () {
    function WechatServer() {
        this.list = [];
    }
    WechatServer.prototype.registerObserver = function (o) {
        this.list.push(o);
    };
    WechatServer.prototype.removeObserver = function (o) {
        for (var i = 0; i < this.list.length; i++) {
            if (this.list[i] === o) {
                this.list.splice(i, 1);
                break;
            }
        }
    };
    WechatServer.prototype.notifyObserver = function () {
        for (var i = 0; i < this.list.length; i++) {
            var oserver = this.list[i];
            oserver.update(this.message);
        }
    };
    WechatServer.prototype.setInfomation = function (s) {
        this.message = s;
        console.log(`微信服务更新消息:${s}`);
        //消息更新,通知所有观察者
        this.notifyObserver();
    };
    return WechatServer;
}());


/**
 * 观察者
 */
var User = (function () {
    function User(name) {
        this.name = name;
    }
    User.prototype.update = function (message) {
        this.message = message;
        this.read();
    };
    User.prototype.read = function () {
        console.log(`${this.name}收到推送消息:${this.message}`);
    };
    return User;
}());



/**
 * 我们来测试
 */
let server = new WechatServer();
let userZhang = new User("张三");
let userLi = new User("李四");
let userWang = new User("王五");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的语言!");
console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的语言!");

观察者模式-es6版
通过这个可以了解到,因为目前包括es2018尚未实现接口、抽象功能,故而无法定义观察者约束性接口,然后还知道了,es6只是语法糖,类似于ts一样,创建类,其实本质就是es5 混合继承知识点:属性用构造,公共函数放在原型对象上,这样所有实例在内存共享一个方法,节省内存,说远了,哈哈不说了,贴代码

/**
 * 被观察者,也就是微信公众号服务
 */
class WechatServer{
    constructor(){
        this.list = [];
    }
    registerObserver(o) {
        this.list.push(o);
    };
    removeObserver(o){
        for (var i = 0; i < this.list.length; i++) {
            if (this.list[i] === o) {
                this.list.splice(i, 1);
                break;
            }
        }
    }
    notifyObserver() {
        for (var i = 0; i < this.list.length; i++) {
            var oserver = this.list[i];
            oserver.update(this.message);
        }
    }
    setInfomation(s){
        this.message = s;
        console.log(`微信服务更新消息:${s}`);
        //消息更新,通知所有观察者
        this.notifyObserver();
    }
}

/**
 * 观察者
 */
class User{
    constructor(name) {
        this.name = name;
    }
    update(message) {
        this.message = message;
        this.read();
    };
    read (){
        console.log(`${this.name}收到推送消息:${this.message}`);
    };
};

/**
 * 我们来测试
 */
let server = new WechatServer();
let userZhang = new User("张三");
let userLi = new User("李四");
let userWang = new User("王五");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的语言!");
console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的语言!");























// var Event = {
//     // 通过on接口监听事件eventName
//     // 如果事件eventName被触发,则执行callback回调函数
//     on: function (eventName, callback) {
//         //我的代码
//         if(!this.handles){
//             this.handles={};
//         }
//         if(!this.handles[eventName]){
//             this.handles[eventName]=[];
//         }
//         this.handles[eventName].push(callback);
//     },
//     // 触发事件 eventName
//     emit: function (eventName) {
//         //你的代码
//         if(this.handles[arguments[0]]){
//             for(var i=0;i<this.handles[arguments[0]].length;i++){
//                 this.handles[arguments[0]][i](arguments[1]);
//             }
//         }
//     }
// };

最后再想哔哔两句:
ts和es6都是语法糖,所以面试的人会问你编译之后会是啥样,挺操dan的,因为java从来不会问我编译后的字节码是什么样
ts跟es6比,就拿这个来说,可以使用接口来约束观察者,防止程序员乱写,可以用数据类型来约束各种参数和返回值,防止乱传,等到了运行再报错,代码我都写了几千行了,谁tm找得到啊。大体来说ts语法约束性较强,是强数据类型语言了,很多错编译阶段就会报错!

clipboard.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题