首页 > 代码库 > leaflet开源地图库源码研读(四)——OOP的基础构建(by vczero)

leaflet开源地图库源码研读(四)——OOP的基础构建(by vczero)

一、贴源码

源码存放的目录是src->core->Class.js

 1 L.Class = function () {}; 2  3 L.Class.extend = function (props) { 4  5     // extended class with the new prototype 6     var NewClass = function () { 7  8         // call the constructor 9         if (this.initialize) {10             this.initialize.apply(this, arguments);11         }12 13         // call all constructor hooks14         if (this._initHooks.length) {15             this.callInitHooks();16         }17     };18 19     // jshint camelcase: false20     var parentProto = NewClass.__super__ = this.prototype;21 22     var proto = L.Util.create(parentProto);23     proto.constructor = NewClass;24 25     NewClass.prototype = proto;26 27     //inherit parent‘s statics28     for (var i in this) {29         if (this.hasOwnProperty(i) && i !== ‘prototype‘) {30             NewClass[i] = this[i];31         }32     }33 34     // mix static properties into the class35     if (props.statics) {36         L.extend(NewClass, props.statics);37         delete props.statics;38     }39 40     // mix includes into the prototype41     if (props.includes) {42         L.Util.extend.apply(null, [proto].concat(props.includes));43         delete props.includes;44     }45 46     // merge options47     if (proto.options) {48         props.options = L.Util.extend(L.Util.create(proto.options), props.options);49     }50 51     // mix given properties into the prototype52     L.extend(proto, props);53 54     proto._initHooks = [];55 56     // add method for calling all hooks57     proto.callInitHooks = function () {58 59         if (this._initHooksCalled) { return; }60 61         if (parentProto.callInitHooks) {62             parentProto.callInitHooks.call(this);63         }64 65         this._initHooksCalled = true;66 67         for (var i = 0, len = proto._initHooks.length; i < len; i++) {68             proto._initHooks[i].call(this);69         }70     };71 72     return NewClass;73 };74 75 76 // method for adding properties to prototype77 L.Class.include = function (props) {78     L.extend(this.prototype, props);79 };80 81 // merge new default options to the Class82 L.Class.mergeOptions = function (options) {83     L.extend(this.prototype.options, options);84 };85 86 // add a constructor hook87 L.Class.addInitHook = function (fn) { // (Function) || (String, args...)88     var args = Array.prototype.slice.call(arguments, 1);89 90     var init = typeof fn === ‘function‘ ? fn : function () {91         this[fn].apply(this, args);92     };93 94     this.prototype._initHooks = this.prototype._initHooks || [];95     this.prototype._initHooks.push(init);96 };
View Code

二、代码分析

(1)在L的命名空间下,定义Class对象,以构造函数的形式给出。 

L.Class = function () {};

 (2)分别给Class对象添加静态方法extend 、include、mergeOptions、addInitHook。

 1 var L = {}; 2 L.Class = function(){}; 3  4  5 /* 6 * 作用:扩展该类的prototype,继承父类的静态函数、静态属性等 7 * 8 * */ 9 L.Class.extend = function(props){};10 /*11  * 作用:添加属性到原型12  * */13 L.Class.include = function (props) {};14 /*15  * 作用:合并默认的options到Class16  * */17 L.Class.mergeOptions = function (options) {};18 /*19  * 作用:添加一个构造函数的钩子20  * */21 L.Class.addInitHook = function (fn){};

(3)分析L.Class.extend函数

贴上L.Class.extend函数的源码:

 1 L.Class.extend = function (props) { 2  3     // extended class with the new prototype 4     var NewClass = function () { 5  6         // call the constructor 7         if (this.initialize) { 8             this.initialize.apply(this, arguments); 9         }10 11         // call all constructor hooks12         if (this._initHooks.length) {13             this.callInitHooks();14         }15     };16 17     // jshint camelcase: false18     var parentProto = NewClass.__super__ = this.prototype;19 20     var proto = L.Util.create(parentProto);21     proto.constructor = NewClass;22 23     NewClass.prototype = proto;24 25     //inherit parent‘s statics26     for (var i in this) {27         if (this.hasOwnProperty(i) && i !== ‘prototype‘) {28             NewClass[i] = this[i];29         }30     }31 32     // mix static properties into the class33     if (props.statics) {34         L.extend(NewClass, props.statics);35         delete props.statics;36     }37 38     // mix includes into the prototype39     if (props.includes) {40         L.Util.extend.apply(null, [proto].concat(props.includes));41         delete props.includes;42     }43 44     // merge options45     if (proto.options) {46         props.options = L.Util.extend(L.Util.create(proto.options), props.options);47     }48 49     // mix given properties into the prototype50     L.extend(proto, props);51 52     proto._initHooks = [];53 54     // add method for calling all hooks55     proto.callInitHooks = function () {56 57         if (this._initHooksCalled) { return; }58 59         if (parentProto.callInitHooks) {60             parentProto.callInitHooks.call(this);61         }62 63         this._initHooksCalled = true;64 65         for (var i = 0, len = proto._initHooks.length; i < len; i++) {66             proto._initHooks[i].call(this);67         }68     };69 70     return NewClass;71 };
View Code

现在,来看NewClass对象,NewClass对象就是创建一个新的内部对象,所有父类的属性和方法都基于此方法。this.initialize就是构造函数。

 1 // extended class with the new prototype 2 var NewClass = function () { 3  4     // call the constructor 5     if (this.initialize) { 6         this.initialize.apply(this, arguments); 7     } 8  9     // call all constructor hooks10     if (this._initHooks.length) {11         this.callInitHooks();12     }13 };

 var parentProto = NewClass.__super__ = this.prototype; 将原型赋给NewClass的_super_属性,并赋值给parentProto。

var proto = L.Util.create(parentProto); //在LeafLet中有个Util.js,该工具类的方法的create方法的作用是:基于给定原型构建对象proto.constructor = NewClass; //对象proto的构造函数指向NewClassNewClass.prototype = proto; //NewClass的原型指向proto,这个大家可以看看原型链的继承方式

附:L.Util.create代码:

// create an object from a given prototype    create: Object.create || (function () {        function F() {}        return function (proto) {            F.prototype = proto;            return new F();        };    })()

接着往下看:

//inherit parent‘s statics    for (var i in this) {        if (this.hasOwnProperty(i) && i !== ‘prototype‘) { //继承父类的静态属性和方法,hasOwnProperty只会遍历自定义属性和方法,不会遍历原型            NewClass[i] = this[i];        }    }

再接着往下看:

// mix static properties into the class    if (props.statics) {        L.extend(NewClass, props.statics); //L.extend == L.Util.extend,在Util.js中便可找到,作用是扩展属性,这里是将props.statics的属性给了NewClass        delete props.statics; //删除该属性    }    // mix includes into the prototype    if (props.includes) {        L.Util.extend.apply(null, [proto].concat(props.includes)); //apply这里巧妙的使用了null, 主要是为了使用extend的功能,将includes和proto的原型结合,连接成一个数组。        delete props.includes; //删除该属性    }

附:L.Util.extend源码

extend: function (dest) {        var i, j, len, src;        for (j = 1, len = arguments.length; j < len; j++) {            src = arguments[j];            for (i in src) {                dest[i] = src[i];            }        }        return dest;    },

接着往下看:

// merge options    if (proto.options) {        props.options = L.Util.extend(L.Util.create(proto.options), props.options); //将options属性合并    }    // mix given properties into the prototype    L.extend(proto, props); //将props的扩展属性,包括原型给proto    proto._initHooks = [];  //初始化空的钩子数组

接着往下看:

// add method for calling all hooks
// 增加一个方法,调用所有的钩子
proto.callInitHooks = function () { if (this._initHooksCalled) { return; } //如果已经调用,直接return if (parentProto.callInitHooks) { //如果父类的原型中存在callInitHooks,则调用父类的callInitHooks parentProto.callInitHooks.call(this); } this._initHooksCalled = true; //设置调用后状态 for (var i = 0, len = proto._initHooks.length; i < len; i++) { proto._initHooks[i].call(this); //调用钩子的数组中的方法 } };

最后一步了,返回对象:

return NewClass;

(4)include:

// method for adding properties to prototypeL.Class.include = function (props) {    L.extend(this.prototype, props);};

(5)mergeOptions:

// merge new default options to the ClassL.Class.mergeOptions = function (options) {    L.extend(this.prototype.options, options);};

(6)addInitHook:

// add a constructor hookL.Class.addInitHook = function (fn) { // (Function) || (String, args...)    var args = Array.prototype.slice.call(arguments, 1);    var init = typeof fn === ‘function‘ ? fn : function () {        this[fn].apply(this, args);    };    this.prototype._initHooks = this.prototype._initHooks || [];    this.prototype._initHooks.push(init);};

三、用图来理理extend函数

 

上一篇:Leaflet开源地图库源码研读(三)——浏览器&移动设备判断(browser.js)(by vczero)

 

leaflet开源地图库源码研读(四)——OOP的基础构建(by vczero)