正在重構整個架構,讓命名空間對象dom也出於同一個繼承體系下,就像mootools1.3的Type對象那樣。
v2的目標大致如下:
- 減少入侵性,只保留ECMA262v5及極個別最有用的擴充,lang模組將與核心模組合而為一
- 模組即純對象,去掉沒有多大用處的protect方法,實現extend與include都能調用父方法
- 去掉構造器中的智能調用父構造器的功能,以後調用父方法統一為this._super()
- 增加不使用new關鍵字就能進行執行個體化(需要在設定物件中配置)
//by 司徒正美 http://www.cnblogs.com/rubylouvre/ 2010.10.14var PROTO = "prototype",CTOR = "constructor",A_proto = Array[PROTO],A_slice = A_proto.slice,to_s = Object[PROTO].toString,is = function (obj,type) { return (type === "Object" && obj === Object(obj)) || (type === "Array" && Array.isArray && Array.isArray(obj)) || // ECMA-5 15.4.3.2 (type === "Null" && obj === null) || (type === "Undefined" && obj === void 0 ) || obj && to_s.call(obj).slice(8,-1) === type;}function extend(target,source){ for(var name in source) if(source.hasOwnProperty(name) && !target[name]){ target[name] = source[name]; } return target;}//Object擴充//fix ie for..in bugvar _dontEnum = [ 'propertyIsEnumerable', 'isPrototypeOf','hasOwnProperty','toLocaleString', 'toString', 'valueOf', 'constructor'];for (var i in { toString: 1}) _dontEnum = false;//第二個參數僅在瀏覽器支援Object.defineProperties時可用extend(Object,{ create:function( proto, props ) {//ecma262v5 15.2.3.5 var ctor = function( ps ) { if ( ps && Object.defineProperties ) Object.defineProperties( this, ps ); }; ctor[PROTO] = proto; return new ctor( props ); }, keys: function(obj){//ecma262v5 15.2.3.14 var result = [],dontEnum = _dontEnum,length = dontEnum.length; for(var key in obj ) if(obj.hasOwnProperty(key)){ result.push(key) } if(dontEnum){ while(length){ key = dontEnum[--length]; if(obj.hasOwnProperty(key)){ result.push(key); } } } return result; }});//用於建立javascript1.6 Array的迭代器function iterator(vars, body, ret) { return eval('[function(fn,scope){'+ 'for(var '+vars+'i=0,l=this.length;i<l;i++){'+ body.replace('_', 'fn.call(scope,this[i],i,this)') + '}' + ret + '}]')[0];};//注釋照搬FF官網extend(Array[PROTO],{ //定位類 返回指定項首次出現的索引。 indexOf: function (el, index) { var n = this.length, i = ~~index; if (i < 0) i += n; for (; i < n; i++) if ( this[i] === el) return i; return -1; }, //定位類 返回指定項最後一次出現的索引。 lastIndexOf: function (el, index) { var n = this.length, i = index == null ? n - 1 : index; if (i < 0) i = Math.max(0, n + i); for (; i >= 0; i--) if (this[i] === el) return i; return -1; }, //迭代類 在數組中的每個項上運行一個函數,若所有結果都返回真值,此方法亦返回真值。 forEach : iterator('', '_', ''), //迭代類 在數組中的每個項上運行一個函數,並將函數返回真值的項作為數組返回。 filter : iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'), //迭代類 在數組中的每個項上運行一個函數,並將全部結果作為數組返回。 map : iterator('r=[],', 'r[i]=_', 'return r'), //迭代類 在數組中的每個項上運行一個函數,若存在任意的結果返回真,則返回真值。 some : iterator('', 'if(_)return true', 'return false'), //迭代類 在數組中的每個項上運行一個函數,若所有結果都返回真值,此方法亦返回真值。 every : iterator('', 'if(!_)return false', 'return true'), //歸化類 javascript1.8 對該數組的每項和前一次調用的結果運行一個函數,收集最後的結果。 reduce: function (fn, lastResult, scope) { if (this.length == 0) return lastResult; var i = lastResult !== undefined ? 0 : 1; var result = lastResult !== undefined ? lastResult : this[0]; for (var n = this.length; i < n; i++) result = fn.call(scope, result, this[i], i, this); return result; }, //歸化類 javascript1.8 同上,但從右向左執行。 reduceRight: function (fn, lastResult, scope) { var array = this.concat().reverse(); return array.reduce(fn, lastResult, scope); }});//修正IE67下unshift不返回數組長度的問題//http://www.cnblogs.com/rubylouvre/archive/2010/01/14/1647751.htmlif([].unshift(1) !== 1){ A_proto.unshift = function(){ var args = [0,0]; for(var i=0,n=arguments.length;i<n;i++){ args[args.length] = arguments[i] } A_proto.splice.apply(this, args); return this.length; //返回新數組的長度 }}//String擴充var metaObject = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},rquote = /[\x00-\x1f\\]/g;extend(String[PROTO],{ //javascript1.5 firefox已實現 quote:function () { var str = this.replace(rquote,function(chr){ var meta = metaObject[chr]; return meta ? meta : '\\u' + ('0000'+chr.charCodeAt(0).toString(16)).slice(-4); }); return '"'+ str +'"'; }, //ecma262v5 15.5.4.20 //http://www.cnblogs.com/rubylouvre/archive/2009/09/18/1568794.html trim: function(){ var str = this.replace(/^(\s|\u00A0)+/, ''), ws = /\s/, i = str.length; while (ws.test(str.charAt(--i))); return str.slice(0, i + 1); }});//Math擴充//http://www.cnblogs.com/rubylouvre/archive/2010/10/09/1846941.htmlvar native_random = Math.random;Math.random = function(min, max, exact) { if (arguments.length === 0) { return native_random(); } else if (arguments.length === 1) { max = min; min = 0; } var range = min + (native_random()*(max - min)); return exact === void(0) ? Math.round(range) : range.toFixed(exact);}extend(Function[PROTO],{ //ecma262v5 15.3.4.5 bind:function(scope) { if (arguments.length < 2 && scope===void 0) return this; var fn = this, argv = arguments; return function() { var args = [], i; for(i = 1; i < argv.length; i++) args.push(argv[i]); for(i = 0; i < arguments.length; i++) args.push(arguments[i]); return fn.apply(scope, args); }; }});function _numarr(s) { // 補零用的輔助函數 var r=[],k=-1,i=0,j,a=s.split(""),z=a.length; for(;i < z;++i){ for(j=0;j < z;++j){ r[++k]=a[i]+a[j]; } } return r;}var numarr = _numarr("0123456789");function toISOString() { var ms = this.getUTCMilliseconds(), pad0 = (ms < 10) ? "00" : (ms < 100) ? "0" : ""; return this.getUTCFullYear() + '-' + numarr[this.getUTCMonth() + 1] + '-' + numarr[this.getUTCDate()] + 'T' + numarr[this.getUTCHours()] + ':' + numarr[this.getUTCMinutes()] + ':' + numarr[this.getUTCSeconds()] + '.' + pad0 + this.getUTCMilliseconds() + 'Z';}extend(Date[PROTO],{//ecma262v515.9.5.43 toISOString:toISOString,//ecma262v5 15.9.5.44 toJSON:toISOString});extend(Date,{//ecma262v5 15.9.4.4 now : function(){ return new Date().valueOf(); }});
全新的類工廠。
var oneObject = function(array,val){ var result = {},value = val !== void 0 ? val :1; for(var i=0,n=array.length;i //---------------------這是樣本-----var MyFirstClass = oop({ message: "hello world", sayHello: function() { p(this.message); }});var obj = new MyFirstClass();obj.sayHello();//hello world//-----------------------------------執行清空擴充類成員以及在類方法中調用超類同方法:
var MyMath = oop({});MyMath.extend({ PI:3.14, getPI:function(){ return this.PI; }});var SonMath = oop({inherit:MyMath});SonMath.extend({ getPI:function(){ return this._super()+0.0015926; }});p(SonMath.getPI());擴充原型成員,extend、include的屬性可以是單個對象,也可以是對象數組。
var movable = { run:function(){ p("能跑") }, fly:function(){ p("能飛") }}var recognition ={ watch:function(){ p("看東西") }, smell:function(){ p("能嗅東西") }}var Robot = oop({ init:function(name,type){ this.name = name; this.type = name; }, include:[movable,recognition]});var chi = new Robot("小嘰","Chobits") ;p(chi.name);chi.watch();chi.fly();配置單例類
var God = oop({ init:function(name){ this.name = name; this.alertName = function(){ p(this.name) } }, singleton:true//注意這裡,使用singleton屬性});var god = new God("耶和華");god.alertName(); //alerts 耶和華var lucifer = new God("撒旦");lucifer.alertName(); //alerts 耶和華p(god === lucifer )//alerts true配置不使用new關鍵字使可以執行個體化。
var dom2 = oop({ init:function(selector){ this.selector = selector return this; }, nonew:true, getSelectors : function(){ return (this.selector ||"").split(/\s+/) } }); p(dom2('.aaa .bbb .ccc').getSelectors())繼承樣本1
var Animal = oop({ init:function(name){ this.name = name; }, getFood:function(){ return "各種各樣的食物" }, extend:{ getClassName:function(){ return "Animal"; } } }); var Human = oop({ inherit:Animal, extend:{ getClassName:function(){ return this._super()+"-->人"; } } }); var me = new Human("john"); p(Human.getClassName()); p(me.getFood()); var Man = oop({ inherit:Human, init:function(name,sex){ this._super(); this.sex = sex; }, getFood: function(){ return this._super()+",尤其是肉類"; } }); var Genghis_Khan = new Man("成吉思汗","男"); p( Genghis_Khan.sex); p( Genghis_Khan.name); p( Genghis_Khan.getFood());繼承樣本2
var Polygon = oop({ init:function(sides){ this.sides = sides }, getArea:function(){ return 0 //此只是個抽象類別,不能用於具體計算 } }); p("==============Triangle===============") var Triangle = oop({ inherit:Polygon, init:function(base,height){ this._super(3); this.base = base; this.height = height; }, getArea:function(){ return 0.5*this.base*this.height; } }); var t = new Triangle(2,6); p(t.sides); p(t.getArea()); p("==============Rectangle===============") var Rectangle = oop({ inherit:Polygon, init:function(length,width){ this._super(4); this.length = length; this.width = width; }, getArea:function(){ return this.length*this.width; } }); var r = new Rectangle(7,6); p(r.sides); p(r.getArea(Rectangle)); p(r instanceof Polygon) p("==============Square===============") var Square = oop({ inherit:Rectangle, init:function(side){ this._super(side,side); } }) var s = new Square(6); p(s.sides); p(s.getArea()) p(s instanceof Polygon) p(s instanceof Square)