首页 > 代码库 > 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 };
二、代码分析
(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 };
现在,来看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)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。