用Backbone有一段时间了,一直在用
var SomeView = Backbone.View.extend({
//...
});
这样的写法,来创建一个View类。
以前忙着先学习基本用法,也没想那么多。今天,不知为何,好奇心泛滥,终于想看看它究竟都干了些什么。
首先先说结论: 上面的代码,可以理解成这样:
var SomeView = function() {
// Default attributes
this.tagName = xxx;
this.cid = xxx;
// Your extend attributes
this.model = xxx;
this.template = xxx;
this.render = xxx;
this.xxx = xxx;
}
实际上,这就是一个典型的用构造模式定义的构造函数,也就是我们通俗所说的javascript的类。
这也就是我们在使用它的时候,可以用
var myView = new SomeView()
的原因。
下面我们就来进一步分析一下,为什么会是这样。
打开Backbonejs官网的源代码页面,在页面上搜索BACKBONE.VIEW
,我们会看到这样一段代码:
var View = Backbone.View = function(options) {
this.cid = _.uniqueId('view');
this._configure(options || {});
this._ensureElement();
this.initialize.apply(this, arguments);
this.delegateEvents();
};
这里就证实了上面说Backbone.View其实就是一个构造函数的说法。
接下来,我们在页面上搜索HELPERS
,找到extend
方法,我们会看到这样一段代码:
var extend = function(protoProps, staticProps) {
var parent = this; // 1
var child;
if (protoProps && _.has(protoProps, 'constructor')) { // 2
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); }; // 3
}
_.extend(child, parent, staticProps);
var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate;
if (protoProps) _.extend(child.prototype, protoProps);
child.__super__ = parent.prototype;
return child;
};
先看看该方法下面的一句话:
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
所以,extend作为一个方法,实际上Model、View、Collection对其都进行了引用。
而当我们在使用
var SomeView = Backbone.View.extend({
//...
});
的时候,实际上是调用了Backbone.View
下面的extend
方法。
然后,我们进入到这个extend
方法里面看看。
1这个地方,将this
赋值给一个parent
变量,我们知道,在Javascript中,this关键字永远都指向函数(方法)的所有者。
所以,当我们执行Backbone.View.extend
的时候,extend
里面的this
就指向View
这个构造函数。
接着往下看,2这个地方,由于我们一般不会传constructor
这个属性,所以,执行3的语句。
3语句是这里的关键。我们把这里的语句换一种方式来写:
child = new Function("return parent.apply(this, arguments);");
这样就能好理解一些了吧,这也就是我们所说的“函数是对象,函数名是指针”的原因了。详细可以去看《javascript高级程序设计》引用类型那一章的Function类型一节的内容。
执行这句的时候,child会自动产生一个prototype的属性,prototype中会有一个constructor的构造函数,这个构造函数就会指向child,而child就是这个匿名函数。
下面的语句干了一些其它的事情,需要注意的是,extend
方法最后,返回了child
。
到这里,完成了Backbone类定义的过程。
调用的过程:
执行new
的时候,会去调用返回值child
的构造函数,也就是刚才提到的那个匿名函数,匿名函数会调用parent
方法,parent
也就是前面提到的View
,而View
正好又是一个构造模型的构造函数,这就是我们都熟悉的东西了,所以就有了前面的结论,从而创建了Backbone对象。
总结:
讲了这么一大堆,主要目的还是希望能起到抱砖引玉的作用,把大家探索本质的好奇心激发起来,这样才能真正的有所得,以至于最终有所为。