网上看到一篇文章,虽然它讲的是一个js库内部的方法,但对我理解js的MVC模式还是很有帮助的,为防止以后访问不了,先抄下来:
$.Class为javascript模拟了继承的实现,他将jquery面向函数的编程和面向对象的编程衔接在一起。$.Class基于 John Resig 的Simple Class类库,除了原型继承外,他还有其他一些特性:静态继承、自描述(Introspection)、命名空间的支持、创建和初始化方法、更容易创建的回调函数。 构造函数 我们通过下面的方式生命一个类型: $.Class( [NAME , STATIC,] PROTOTYPE ) -> Class Name{可选:字符串}:如果设置了,将会把它作为fullName和shortName的值,并添加相应的命名空间。 Static{可选:Object对象}:如果设置了,会为Class添加静态的属性和方法。 Prototype:{Object对象}:为Class添加原型的属性和方法。 当Class被创建的时候,静态的setup和init方法将会被执行。实例化一个类型的方式如下,并且原型的setup和init方法会在这一过程中被执行: new Class([args ... ]) -> instance 静态属性vs原型属性 在开始学习Class之前,弄清楚静态属性和原型属性的区别是很重要的,我们来看例子: //静态 MyClass.staticProperty //共享属性 //原型 myclass = new MyClass() myclass.prototypeMethod() //实例方法 这里的静态和原型属性和c#,java中的静态和原型属性在使用上比较相似,只是实现的机制不一样。静态属性是类对象(而不是他的实例)本身具有的属性,在$.Class中我们可以使用this.constructor.XXX的方式访问它,但是在传统的javascript编程中只能通过Class.Property的方式访问,就像上例;原型属性是从原型链上继承下来的,或者是实例对象本身具有的。 一个基本的类 下面的例子创建了一个名叫Monster的类。 $.Class(‘Monster‘, /* 这里定义的是静态属性 */ { count: 0 }, /* 这里定义的是原型属性 */ { init: function( name ) { // 将name变量保存到实例的name属性中 this.name = name; // 设置health为10 this.health = 10; // 使用 this.constructor.XXX 的方式可以访问到静态属性,这里自增count属性的值 this.constructor.count++; }, eat: function( smallChildren ){ this.health += smallChildren; }, fight: function() { this.health -= 2; } }); hydra = new Monster(‘hydra‘); dragon = new Monster(‘dragon‘); hydra.name // -> hydra Monster.count // -> 2 Monster.shortName // shortName是$.Class自带的一个静态属性 -> ‘Monster‘ hydra.eat(2); // health = 12 dragon.fight(); // health = 8 原型属性中的init方法相当于构造函数,本次实例化对象的时候,都会执行。 继承 当一个类被别的类扩展之后,他的所有静态和原型属性都会被继承。当你重写一个函数的时候,你可以通过使用this._super()访问他在父类中的实现。我们来创建一个新类SeaMonster : Monster("SeaMonster",{ eat: function( smallChildren ) { this._super(smallChildren / 2); }, fight: function() { this.health -= 1; } }); lockNess = new SeaMonster(‘Lock Ness‘); lockNess.eat(4); //health = 12 lockNess.fight(); //health = 11 静态属性的继承 你可以像这样实现静态属性的继承: $.Class("First", { staticMethod: function() { return 1;} },{}) First("Second",{ staticMethod: function() { return this._super()+1;} },{}) Second.staticMethod() // -> 2 命名空间 命名空间是个好东西,使用它可以把你的代码按功能分割,程序架构上更加合理;而且便于把代码移植到别的地方,而不用担心异常的产生。javascript本身不支持命名空间,所以只有采取一种变通的方式,例如我们可以使用单例模式。下面是$.Class中使用命名空间的例子: $.Class("MyNamespace.MyClass",{},{}); new MyNamespace.MyClass() 自描述(Introspection) $.Class为类提供了字符串的名称实现自我表述的功能,看下例: $.Class("MyOrg.MyClass",{},{}) MyOrg.MyClass.shortName //-> ‘MyClass‘ MyOrg.MyClass.fullName //-> ‘MyOrg.MyClass‘ fullName包括命名空间,shortName不包括命名空间,他们都是静态属性。 创建和初始化方法 $.Class提供了静态的和原型的初始化方法,以方便你完成类的创建,他们是setup和init。setup将会在init之前运行,一般情况下你不需要使用到他,但当你需要为init做一些复杂的工作,比如初始化init需要使用的参数时可以使用它。 $.Class("MyClass", { setup: function() {} //static setup init: function() {} //static constructor }, { setup: function() {} //prototype setup init: function() {} //prototype constructor }) 1.Setup: setup在init之前被调用,静态setup函数把基类的参数传递给扩展类,原型函数传递构造函数参数。如果setup返回数组,数组会作为init方法的参数,这样可以吧一些默认参数传递给init方法。你也可以再setup中放置经常要运行的代码。你不需要重写setup方法。 $.Class("jQuery.Controller",{ ... },{ setup: function( el, options ) { ... return [$(el), $.extend(true, this.Class.defaults, options || {} ) ] } }) 2.Init: init方法在setup之后运行,他们接收setup的结果作为参数。 $.Class("Foo", { init: function( arg1, arg2, arg3 ) { this.sum = arg1+arg2+arg3; } }) var foo = new Foo(1,2,3); foo.sum //-> 6 代理 和jquery提供的代理方法类似,他返回一个回调函数,this总是指向Class或者Class的实例。下面例子中使用this.proxy以确保this.name是指向Todo实例的,这样show是就可以得到正确的值。 $.Class("Todo",{ init: function( name ) { this.name = name }, get: function() { $.get("/stuff",this.proxy(‘show‘)) }, show: function( txt ) { alert(this.name+txt) } }) new Todo("Trash").get()
javascriptMVC入门 -- 3.jQueryMX -> $.Class
入门级js都是一些零散的function,然后搞一个start();方法,其内部执行所有页面loading后初始化要执行的方法。
然后一些牛人喜欢把自己的代码封装好了变成像插件一样可以重复利用,甚至还自定义标签。
但是,有一个我认为是误区的地方: 一个网站不可能处处都是封装好的插件,而你封装了自己的插件,并不代表其他部分的零散代码就可以没有思路清晰的结构。
我在读一个非常喜欢封装的牛人的代码的时候常常会发现他封装得太多,导致后期维护修改的问题,连他自己也常常忘记自己写的是什么意思了。。。
于是有后台的强人跟我说,你不能学他这样,你应该去看看《设计模式》,学学MVC。
虽然还没有好好去看过这本书,不过已经开始依样画葫芦学人家重构我的JS了。
学习上篇 P. R. May 写的global.js的结构:
<head> <script type="text/javascript"> $(function(){Suli.init();}); </script> </head> var Suli = Suli || {};
Suli.init = function () { new Suli.Functioname(); }
Suli.Functioname = function () { api :{ init = function (){ } }, _fun = function ( ) { }, api = { anything : function () { }, dosomething : function () { }, ... return api.init(); }
把相关功能都放到一个具有标志性的函数中,该函数具有一个api对象,在api的init方法中执行子方法,return含有init方法的对象,在这个函数被实例化的的同时它就称为了一个构造函数。
优化!优化!
时间: 2024-11-11 13:42:50