1.svelte的优势,没有劫持、没有虚拟DOM等,纯编译响应式,它可能是未来的趋势(是编译器,已经不是框架了)
    2.vue2,关于响应式的原理大概如下:

    1. // 单一职责,解耦
    2. export class Vue {
    3. constructor(options = {}) {
    4. this.$options = options
    5. this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el
    6. this.$data = options.data
    7. this.$methods = options.methods
    8. this.proxy(this.$data)
    9. // Observe 拦截this.$data
    10. new Observer(this.$data)
    11. // 编译html
    12. new Compiler(this)
    13. }
    14. // 代理,方便使用,直接this.name
    15. proxy(data) {
    16. Object.keys(data).forEach(key => {
    17. Object.defineProperty(this, key, {
    18. enumerable: true,
    19. configurable: true,
    20. get() {
    21. return data[key]
    22. },
    23. set(newValue) {
    24. if(data[key] === newValue || (Number.isNaN(data[key] && Number.isNaN(newValue)))) {
    25. return
    26. }
    27. data[key] = newValue;
    28. }
    29. })
    30. })
    31. }
    32. }
    33. // 发布订阅模式
    34. class Dep {
    35. constructor() {
    36. this.deps = new Set()
    37. }
    38. // 收集副作用代码
    39. add() {
    40. if (dep && dep.update) {
    41. this.deps.add(dep);
    42. }
    43. }
    44. notify() {
    45. // udpate就是执行副作用 Watcher
    46. this.deps.forEach(dep => dep.udpate())
    47. }
    48. }
    49. // watcher会在编译的时候触发,编译html中的变量->触发当前变量的getter->封装一个watcher
    50. class Watcher {
    51. constructor(vm, key, cb) {
    52. // vm是vue实例
    53. this.vm = vm;
    54. this.key = key;
    55. this.cb = cb;
    56. Dep.target = this;
    57. this.__old = vm[key] // 存下初始值,触发getter
    58. // 防止我们在别处触发getter,仅在编译的时候
    59. Dep.target = null;
    60. }
    61. update() {
    62. let newValue = this.vm[this.key]
    63. if (this.__old === newValue) {
    64. return;
    65. }
    66. this.cb(newValue); // 操作DOM的函数
    67. }
    68. }
    69. class Observer {
    70. constructor(data) {
    71. this.walk(data)
    72. }
    73. walk(data) {
    74. if(!data || typeof data !== 'object') return
    75. Object.keys(data).forEach(key => this.defineReactive(data, key, data[key]))
    76. }
    77. // { obj: }
    78. defineReactive(obj, key, value) {
    79. let that = this;
    80. let dep = new Dep();
    81. this.walk(value);// 这个放在后面可以吗?
    82. Object.defineProperty(obj, key, {
    83. configurable: true,
    84. enumerable: true,
    85. get() {
    86. Dep.target && dep.add(Dep.target)
    87. return value;
    88. },
    89. set(newValue) {
    90. value = newValue;
    91. // 赋值的这个也可能是一个对象
    92. that.walk(newValue);
    93. dep.notify()
    94. }
    95. })
    96. }
    97. }
    98. class Compiler {
    99. constructor(vm) {
    100. this.el = vm.$el
    101. this.vm = vm
    102. this.methods = vm.$methods
    103. this.compiler(vm.$el)
    104. }
    105. compiler(el) {
    106. let childNodes = el.childNodes
    107. Array.from(childNodes).forEach(node => {
    108. if (this.isTextNode(node)) {
    109. this.compileText(node)
    110. } else if (this.isElementNode(node)) {
    111. this.compileElement(node)
    112. }
    113. // 递归编译子节点
    114. if (node.childNodes && node.childNodes.length) {
    115. this.compiler(node)
    116. }
    117. })
    118. }
    119. compileElement(node) {
    120. if(node.attributes.length) {
    121. Array.from(node.attributes).forEach(attr => {
    122. let attrName = attr.name
    123. // v-on:click and v-model
    124. if(this.isDirective(attrName)) {
    125. attrName = attrName.indexOf(':') > -1 ? attrName.substr(5) : attrName.substr(2)
    126. let key = attr.value
    127. this.update(node, key, attrName, this.vm[key])
    128. }
    129. })
    130. }
    131. }
    132. udpate(node, key, attrName, value) {
    133. if (attrName === 'text') {
    134. node.textContent = value
    135. // 如果加上虚拟DOM diff算法的话,此处的回调函数就不应该直接操作DOM了,应该传入新老树进行对比,最后再渲染
    136. new Watcher(this.vm, key, val => {
    137. node.textContent = val
    138. })
    139. } else if (attrName === 'model') {
    140. node.value = value
    141. new Watcher(this.vm, key, val => {
    142. node.textContent = val
    143. })
    144. node.addEventListenner('input', () => {
    145. this.vm[key] = node.value
    146. })
    147. } else if (attrName === 'click') {
    148. node.addEventListenner('click', this.methods[key].bind(this.vm))
    149. }
    150. }
    151. isDirective(str) {
    152. return str.startsWith('v-')
    153. }
    154. // 元素节点 <div v-model="msg"></div>
    155. isElementNode(node) {
    156. return node.nodeType === 1
    157. }
    158. // {{ count}} 文本节点
    159. compileText(node) {
    160. let reg = /\{\{(.+?)\}\}/
    161. let value = node.textContent
    162. if(reg.test(value)) {
    163. let key = RegExp.$1.trim()
    164. node.textContent = value.replace(reg, thiis.vm[key])
    165. new Watcher(this.vm, key, val => {
    166. node.textContent = val
    167. })
    168. }
    169. }
    170. isTextNode(node) {
    171. return node.nodeType === 3
    172. }
    173. // 缺少调度啊???
    174. // 没有考虑作用域?????
    175. }

    3.vue3.0相关响应式如下:
    最大的优势: 考虑到内存的问题,不用每次都像2.0那样,new Dep()

    // vue3.0
    function isObject(data) {
        return data && typeof data === 'object'
    }
    export function reactive(data) {
        if(!isObject(data)) return
        return new Proxy(data, {
            get(target, key, receiver) {
                const ret = Reflect.get(target, key, receiver);
                // 依赖收集
                track(target, key)
                return isObject(ret) ? reactive(ret) : ret
            },
            set(target, key, value, receiver) {
                return Reflect.set(target, key, value, receiver);
            },
            deleteProperty(target, key, receiver) {
                const ret = Reflect.deleteProperty(target, keu, receiver)
                // todo 通知
                return ret
            }
        })
    }
    // proxy无法监听基本类型, 采用一个对象包起来
    export function ref(target) {
        let value = target
        const obj = {
            get value() {
                track(obj, 'value')
                return value
            },
            set value(newValue) {
                if (value === newValue) return
                value = newValue
                trigger(obj, 'value')
            }
        }
        return obj
    }