美文网首页
JavaScript发布订阅模式与defineProperty模

JavaScript发布订阅模式与defineProperty模

作者: 罗坤_23333 | 来源:发表于2018-09-13 16:13 被阅读0次

什么是发布-订阅模式?

发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。在JavaScript开发中,我们一般用事件模型来替代传统的发布-订阅模式。[1]
DOM节点绑定事件函数是最常用的发布-订阅模式

//订阅点击事件
document.body.addEventListener( 'click', function(){
  alert(2)
}, false )

document.body.click();  //模拟用户点击

//取消订阅点击事件
document.body.removeEventListener( 'click' )

Object.defineProperty

我们平时能轻松创建、修改对象,都是基于以下特性↓
JavaScript的对象有两种内部属性类型:数据属性访问器属性

数据属性承载(payload)对象指定属性的值([[Value]])以及控制其是否可被修改([[Writable]])或者是否可被删除([[Configurable]])和是否可被for-in循环返回到[[enumerable]],是对内的属性。
访问器属性,对外的属性。在读取属性时,会调用getter函数,这个函数负责返回有效的值;在修改属性值时,会调用setter函数承载传入的新值并决定如何处理数据。这两个函数都是可以被重写的。
而以上这些功能必须使用Object.defineProperty()方法实现

Tips: vue.js就是利用Object.defineProperty()的访问器思想来更新视图的。
IE8是第一个实现Object.defineProperty()的浏览器版本。然而这个版本实现存在诸多限制:只能在DOM对象上使用这个方法,而且只能创建访问器属性[2]。由于实现不彻底被不建议开发者使用,但在IE9得到改善,所以vue.js只能兼容到IE9及以上版本。

get and set在ES6的表现

ES6中的新语法class类也很好地保留了 类似访问器属性

class Person {
        constructor(name, age){
            this.name = name;
            this.age = age;
            this.innerTitle = "";

        }
        get title(){
            return this.innerTitle;
        }
        set title(value){
            this.innerTitle = value;
        }

        sayName(){
            alert(this.name);
        }
        getOlder(years){
            this.age += years;
        }
    }
    var p = new Person('Niko',24)
    p.title = 'asd'
    console.log(p.title)    //asd

基于设计模式和Object.defineProperty简单实现vue双向绑定模型

基本思路:

  • 利用Object.defineProperty监听对象赋值动作,
  • 遍历所有节点,
  • 使用观察者模式对拥有‘v-model’属性的DOM节点订阅上述事件
  • 对拥有‘v-bind’属性的DOM节点进行发布事件
  • 针对表单标签仅监听addEventListener('input',function(e){...})事件
图片资源来自[3]

HTML

<div id="app">
    <textarea cols="30" rows="10" v-model="asd"></textarea>
    <h1 v-bind="asd"></h1>
    <h1 v-bind="qwe"></h1>
</div>

观察者对象

   const _observer = {
        //存储消息列表
        clientList:{},
        //监听消息
        listen:function(key,fn){
            if(!this.clientList[key]){
                this.clientList[key] = []
            }
            this.clientList[key].push(fn)
        },
        //发布消息
        trigger:function(key,data){
            let fns = this.clientList[key];
            if(!fns || fns.length === 0) {
                return false;
            }
            for(let i=0,fn;fn = fns[i++];){
                fn.call(this,data);
            }
        }
    };

具体实现

    // 遍历app所有节点
    let nodes = document.querySelector('#app').children;
    // v-model节点对象
    let vModelList = Object.create(null);
    for(let i=0,node;node=nodes[i++];) {
        //存储v-model nodes
        if (node.hasAttribute('v-model')) {
            let key = node.getAttribute('v-model');
            //添加表单监听事件
            node.addEventListener('input', function (e) {
                vModelList[key] = e.target.value
            });
            /**
             * 核心 Object.defineProperty
             * **/
            //监听vModelList对象指定key值变化
            Object.defineProperty(vModelList, key, {
                enumerable: true,
                configurable: true,
                set: function (newVal) {
                    // 发布
                    _observer.trigger(key, newVal)
                }
            });
        }

        //存储v-bind nodes
        if (node.hasAttribute('v-bind')) {
            let key = node.getAttribute('v-bind');
            // 订阅
            _observer.listen(key, function (newVal) {
                node.innerHTML = newVal //这里只用innerHTML简单实现,未使用模版引擎
            })
        }
    }

相关文章

  • JavaScript发布订阅模式与defineProperty模

    什么是发布-订阅模式? 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变...

  • Javascript 发布-订阅模式

    Javascript 发布-订阅模式 本文内容搬运于:Javascript中理解发布-订阅模式,虽是搬运,但纯手打...

  • vue2

    Vue的双向绑定原理(扩展) Object.defineProperty 观察者模式(发布-订阅模式) 计算属性 ...

  • js实现双向数据绑定 2019-08-14

    Object.defineProperty方法属性拦截的方式结合发布订阅模式实现

  • Vue双向数据绑定

    Vue 的双向数据绑定采用defineProperty(3.0以前) 以及 发布订阅模式来实现的。definePr...

  • vue的双向绑定原理

    1,Vue.js 采用的是 数据劫持+发布/订阅模式 的方式,通过 Object.defineProperty()...

  • Javascript 发布订阅模式

    发布订阅模式分为为两部分 on 和 emit on 收集函数到一个数组 emit 依次执行这些函数 更新一版

  • Vue的响应式原理

    vue数据双向绑定是通过数据劫持(Object.defineProperty)+发布者-订阅者模式来实现的 发布者...

  • JavaScript设计模式六(发布-订阅模式)

    JavaScript设计模式六(发布-订阅模式) 发布-订阅模式又叫做观察者模式,定义: 定义对象间的一种一对多的...

  • Vue 速记

    响应原理 vue 采用水街吃结合 ‘发布者-订阅者模式’ 的方式,通过 Object.defineProperty...

网友评论

      本文标题:JavaScript发布订阅模式与defineProperty模

      本文链接:https://www.haomeiwen.com/subject/paowgftx.html