backbond Model实现

时间:2022-02-25 07:18:58

backbond中的M,指的是模型,即存放数据以及数据相关逻辑的单位。在分析其结构之前,先看一下其调用过程。

<script>

    (function ($) {
World = Backbone.Model.extend({
initialize: function(){
alert('Hey, you create me!');
},
defaults: {
name:'张三',
age: '38'
}
}); var wodld = new World({x:1});
var x = new World({y:2}); })(jQuery);

backbond 通过Backbone.Model.extend方法得到一个World类(为了不让World和其实例化结果混淆,这里把World称为类,实例化结果称为对象),再通过实例化World来获得实例对象,并调用类中的initialize方法。这看起来和java很相似,也就是一种面向对象的编程方法。

在前面的backbond架构分析中,我们知道Backbone.Model.extend就是extend函数,从extend入手分析,先看一下extend在内部的实现。

var extend = function(protoProps, staticProps) {
var parent = this;
var child; // 如果传入的对象中存在属性为construtor,那么将其构造函数作为child
// 否则,child作为一个调用父类的方法
if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); };
}
// 调用underscore的extend方法 将传入的第二个参数添加进child
_.extend(child, parent, staticProps); // 对原型链进行设置 通过创建一个surrogate来使得child的原型链获得parent原型链
// 如果直接赋值 即child.prototype = parent.prototype,那么对child.prototype的改造也会影响到parent.prototype
var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate; // Add prototype properties (instance properties) to the subclass,
// if supplied.
if (protoProps) _.extend(child.prototype, protoProps); // 最后,由于上面的改造原型链,需要将child的上一层原型改为parent
child.__super__ = parent.prototype;
return child;
};

在extend中,最后返回的是一个函数,也就是上面例子中的World类,extend中的parent也就是Backbone.Model,即使得返回的函数的原型上具有Model和我们传入的属性。

接下来就是Model函数了,

var Model = Backbone.Model = function(attributes, options) {
//设置属性
var attrs = attributes || {};
options || (options = {});
this.cid = _.uniqueId('c');
this.attributes = {};
if (options.collection) this.collection = options.collection;
if (options.parse) attrs = this.parse(attrs, options) || {};
attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
this.set(attrs, options);
this.changed = {};
//调用initialize函数
this.initialize.apply(this, arguments);
};

我们知道,在js中使用new字符调用一个函数时,也就是创建了一个对象,this指向了这个对象并使该对象继承了构造函数的原型链,最后如果返回结果不是一个对象的话就返回这个对象。

那么在上面的例子中,最后通过了var world = new World({x:1});调用了World类,

而一开始我们在构造World类时并没有传入具有属性为constructor的对象,也就是说 World = function(){ return BackBond.Model.apply(this, arguments); };

其中的this就是新创建的对象,那么就在新创建的对象下调用了Backbond.Model,最后返回了这个对象,也就是我们上面的world对象。

最后我们在调试器打印出world对象。

backbond Model实现

最后,总结一下backbond具体的设计思路:

   1: 定义Model函数,并在其原型上设置一系列方法。

2.1: 通过extend函数,获得一个函数(也就是我们创建的类),其原型继承了Model函数原型

2.2: 并根据我们传入的参数设置类为一个构造函数或者通过apply将上下文设置为我们的实例化对象来调用Model函数的函数(即初始化,并调用initlize函数,相当于java的构造函数)。

2.3: 最后返回类。

   3: 实例化父类,获得对象。

这样的设计最终会使得我们像使用面向对象语言一样来使用Js。(类,构造函数,对象,继承...)。