Backbone源码研究 – Backbone.Model

前言

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

伪代码

先来看看 Model 的构造函数

    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._changing 和 this._pending 的使用场景,感觉是一个当多个 set 同时执行时候的一个标记位,但是 JS 是单线程执行,里面又都是 for 语句,按理说可以不用这两个标记位。又或者是我的理解有误。

more

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏nnngu

经典Java面试题收集

1、面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象...

54860
来自专栏Java3y

Java锁机制了解一下

30060
来自专栏逍遥剑客的游戏开发

J2ME 的优化措施

20570
来自专栏Java3y

【Java】几道常见的秋招面试题

Redis目前还在看,今天来分享一下我在秋招看过(遇到)的一些面试题(相对比较常见的)

18720
来自专栏IMWeb前端团队

@ts-check

本文作者:IMWeb elvin 原文出处:IMWeb社区 未经同意,禁止转载 由于 JavsScript是弱类型,所以在大型项目中使用时显得能力略有...

29880
来自专栏偏前端工程师的驿站

前端魔法堂——异常不仅仅是try/catch

14230
来自专栏极客编程

ECMAScript 6教程 (一)

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文连接,博客地址为 http://www.cnblogs.co...

10120
来自专栏MasiMaro 的技术博文

使用MSHTML解析HTML页面

最近在写一个爬虫项目,本来打算用C/C++来实现,在网上查找有关资料的时候发现了微软的这个MSHTML库,最后发现在解析动态页面的时候它的表现实在是太差:在项目...

38830
来自专栏小古哥的博客园

常用表单验证插件

插件地址:https://github.com/gavin125/gavin-Vtype 主要用正则的方式匹配输入内容的格式 ? 分为两个版本: 1、Vtype...

39540
来自专栏Coco的专栏

BAT及各大互联网公司2014前端笔试面试题--JavaScript篇

34950

扫码关注云+社区

领取腾讯云代金券