资讯专栏INFORMATION COLUMN

Backbone源码研究 - Backbone.Model

Steve_Wang_ / 2744人阅读

摘要:用到了一个小技巧来防止误传入的覆盖掉默认的值。的精粹都在这个函数里面。看到这,给各种打补丁就有了可行性,支持就用,不支持的则降级到走的这种方式。

前言

都因为 IE8 不支持 Object.defineProperty,但是业务还不能脱离 IE7 和 IE8,故研究下 Backbone.Model 的实现机制,找机会给主流的 MVVM 框架补丁

伪代码

先来看看 Model 的构造函数

var Model = Backbone.Model = function(attributes, options) {
    var attrs = attributes || {};
    options || (options = {});
    
    // 钩子
    this.preinitialize.apply(this, arguments);
    
    // 每个实例分配一个唯一的 cid
    this.cid = _.uniqueId(this.cidPrefix);
    // 数据对象
    this.attributes = {};
    
    // 不重要的内容
    if (options.collection) this.collection = options.collection;
    if (options.parse) attrs = this.parse(attrs, options) || {};
    
    // 获取预设在 defaults 字段中的初始键值对或匿名函数
    // 这里使用 _.result() 来兼容函数和对象两种类型
    var defaults = _.result(this, "defaults");
    
    // 避免 attrs 中的 undefined 值覆盖掉 defaults 中的默认值
    attrs = _.defaults(_.extend({}, defaults, attrs), defaults);
    
    // 初始化赋值
    this.set(attrs, options);
    this.changed = {};
    
    // 钩子
    this.initialize.apply(this, arguments);
  };

很简单的代码,做了一些初始化赋值的事情。

用到了一个小技巧 attrs = _.defaults(_.extend({}, defaults, attrs), defaults); 来防止误传入的 undefined 覆盖掉默认的 defaults 值。

Backbone 的精粹都在 set(){} 这个函数里面。

set: function(key, val, options) {
  if (key == null) return this;

  // 统一 "key", "val" 和 {key:val} 这两种形式
  // attrs 最终为变动的对象
  var attrs;
  if (typeof key === "object") {
    attrs = key;
    options = val;
  } else {
    (attrs = {})[key] = val;
  }

  options || (options = {});

  // 规则验证.
  if (!this._validate(attrs, options)) return false;

  var unset      = options.unset;
  var silent     = options.silent;
  var changes    = [];
  var changing   = this._changing;
  this._changing = true;

  // 预留上一次的值
  if (!changing) {
    this._previousAttributes = _.clone(this.attributes);
    this.changed = {};
  }

  // 备份一个当前的数据对象
  var current = this.attributes;
  var changed = this.changed;
  var prev    = this._previousAttributes;

  // 遍历传入的新数据对象
  for (var attr in attrs) {
    val = attrs[attr];
    
    // 如果新数据与当前不一致,则标记变动的键名
    if (!_.isEqual(current[attr], val)) changes.push(attr);
    
    // 如果新数据与旧数据不一致,则更新已变动的数据备份
    if (!_.isEqual(prev[attr], val)) {
      changed[attr] = val;
    } else {
      delete changed[attr];
    }
    
    // 真正干活的代码,更新数据或者删除数据
    unset ? delete current[attr] : current[attr] = val;
  }

  // 更新 id 字段
  if (this.idAttribute in attrs) this.id = this.get(this.idAttribute);

  if (!silent) {
    if (changes.length) this._pending = options;
    
    // 遍历变动清单,并且逐个触发 `change:` 事件
    for (var i = 0; i < changes.length; i++) {
      this.trigger("change:" + changes[i], this, current[changes[i]], options);
    }
  }

  if (changing) return this;
  if (!silent) {

    // 触发一个总的 `change` 事件
    // 注释说这里用 while 是确保嵌套场景也只触发一个 `change` 事件
    while (this._pending) {
      options = this._pending;
      this._pending = false;
      this.trigger("change", this, options);
    }
  }
  this._pending = false;
  this._changing = false;
  return this;
},

整个 set 里面,实际干活的就是 unset ? delete current[attr] : current[attr] = val;

没看明白 this._changingthis._pending 的使用场景,感觉是一个当多个 set 同时执行时候的一个标记位,但是 JS 是单线程执行,里面又都是 for 语句,按理说可以不用这两个标记位。又或者是我的理解有误。

more

看到这,给各种Observer打补丁就有了可行性,支持 Object.defineProperty 就用 Object.defineProperty,不支持的则降级到走 Backbone 的这种 for in 方式。

同步更新博客

https://www.mxgw.info/a/backb...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81330.html

相关文章

  • Backbone源码研究 - Backbone.View

    摘要:整个的代码非常简洁,构造逻辑也一目了然。生成唯一合并参数列表列表项目的初始化用户定义的初始化事件处理可以看到,最重要的代码,在于的初始化。这段代码可以看出,如果实例化的时候有传入一个节点,则绑定这个节点,否则生成一个这样的节点。 整个View的代码非常简洁,View构造逻辑也一目了然。 javascriptvar View = Backbone.View = function(opt...

    JellyBool 评论0 收藏0
  • Backbone 源码解读(一)

    1. 开场 1.1 MVC? MVC是一种GUI软件的一种架构模式。它的目的是将软件的数据层(Model)和视图(view)分开。Model连接数据库,实现数据的交互。用户不能直接和数据打交道,而是需要通过操作视图,然后通过controller对事件作出响应,最后才得以改变数据。最后数据改变,通过观察者模式更新view。(所以在这里需要用到设计模式中的观察者模式) 1.2 Smalltalk-80...

    Kosmos 评论0 收藏0
  • Backbone.js学习笔记(二)细说MVC

    摘要:因为是一条数据记录,也就是说,相当于是一个数据集。通常我们需要重载函数,声明,以及通过或为视图指定根元素。通过绑定视图的函数到模型的事件模型数据会即时的显示在中。实例属性参数以及类属性参数会被直接注册到集合的构造函数。 对于初学backbone.js的同学可以先参考我这篇文章:Backbone.js学习笔记(一) Backbone源码结构 showImg(https://segme...

    taoszu 评论0 收藏0
  • Backbone源码解读(二)

    摘要:以为例构造函数的内容构造函数的内部一般会做以下几个操作各种给内部对象设置属性。为什么呢源码做出了解释。在里面会调用用户传入的回调函数并触发事件表示已经同步了。整个的源码事实上就是这两组东西。 1. 开场 强烈建议一边看着源码一边读本文章,本文不贴大段代码。源码地址。在写backbone应用的时候,说实话,大部分的时间都是在写这三个模块的内容。关于这三个模块的分析网上随随便便就能找到一堆...

    Sleepy 评论0 收藏0
  • backbone源码解读

    摘要:个人认为,读懂老牌框架的源代码比会用流行框架的要有用的多。另外,源代码中所有的以开头的方法,可以认为是私有方法,是没有必要直接使用的,也不建议用户覆盖。 写在前面 backbone是我两年多前入门前端的时候接触到的第一个框架,当初被backbone的强大功能所吸引(当然的确比裸写js要好得多),虽然现在backbone并不算最主流的前端框架了,但是,它里面大量设计模式的灵活运用,以及令...

    Kross 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<