Object.defineProperty(Object.prototype,"description",{
writable:true,
enumerable:false,
configurable:true,
value:function(){
console.log(this);
}
});
function inherit(p){
if(p == null) throw TypeError();
if(Object.create) return Object.create(p);
var type = typeof p;
if(type !== "object" && type !== "function") throw TypeError();
function fun(){};
fun.prototype = p;
return new fun();
}
function extend(o,p)
{
for(prop in p){
o[prop] = p[prop];
}
return o;
}
"=============类和原型".description()
function range(from,to){
var r = inherit(range.methods);
r.from = from;
r.to = to;
return r;
}
range.methods = {
includes:function(x){
return this.from <= x && this.to >= x;
},
foreach:function(fun){
for(var x = Math.ceil(this.from); x <= this.to; x++) fun(x);
},
toString:function(){return "(" + this.from + "..." + this.to + ")";}
}
var r = range(1,3);
r.description();
r.toString().description();
r.includes(2).description();
r.foreach(console.log);
"=============类和构造函数".description()
function Range(from,to){
this.from = from;
this.to = to;
};
Range.prototype = {
includes:function(x){
return this.from <= x && this.to >= x;
},
foreach:function(fun){
for(var x = Math.ceil(this.from); x <= this.to; x++) fun(x);
},
toString:function(){return "(" + this.from + "..." + this.to + ")";}
};
var r = new Range(1,3)
r.description();
r.toString().description();
r.includes(2).description();
r.foreach(console.log);
"--------构造函数和类的标识".description();
(r instanceof Range).description();
"--------constructor属性".description();
var F = function(){};
var p = F.prototype;
var c = p.constructor;
(c === F).description();
(F.prototype.constructor === F).description();
var o = new F();
(o.constructor === F).description();
(r.constructor === Range).description();
Range.prototype = {
constructor:Range,
includes:function(x){
return this.from <= x && this.to >= x;
},
foreach:function(fun){
for(var x = Math.ceil(this.from); x <= this.to; x++) fun(x);
},
toString:function(){return "(" + this.from + "..." + this.to + ")";}
};
var r1 = new Range(2,4);
(r1.constructor === Range).description();
function Range2(from,to){
this.from = from;
this.to = to;
}
Range2.prototype.includes = function(x){return this.from <= x && this.to >= x;};
var r2 = new Range2();
(r2.constructor === Range2).description();
"=============JavaScript中Java式的类继承".description()
function defineClass(constructor,methods,statics)
{
if(methods) extend(constructor.prototype,methods);
if(statics) extend(constructor,statics);
}
function Complex(real,imaginary)
{
if(isNaN(real) || isNaN(imaginary))
throw new TypeError();
this.real = real;
this.imaginary = imaginary;
}
Complex.prototype.add = function(that){
return new Complex(this.real + that.real,this.imaginary + that.imaginary);
}
Complex.prototype.toString = function(){
return "{" + this.real + "," + this.imaginary + "}";
}
Complex.ZERO = new Complex(0,0);
Complex.parse = function(s){
try{
var m = Complex._format.exec(s);
return new Complex(parseFloat(m[1]),parseFloat(m[2]));
}catch(x){
throw new TypeError("Can't parse '" + s + "' as a complex number .");
}
};
Complex._format = /^\{([^,]+),([^}]+)\}$/;
var a = new Complex(2,3);
var b = new Complex(4,5);
a.add(b).toString().description();
Complex.parse("{9,9}").description();
Complex.ZERO.description();
"=============类的扩充".description();
Complex.prototype.conj = function(){return new Complex(this.real,-this.imaginary);};
Complex.parse("{5,9}").conj().description();
"=============类和类型".description();
"------------- instanceof运算符".description();
var cmpx = new Complex(1,4);
(cmpx instanceof Complex).description();
(cmpx instanceof Object).description();
range.methods.isPrototypeOf(range(1,3)).description();
"------------- constructor运算符".description();
function typeAndValue(x){
if(x == null) return "";
switch(x.constructor){
case Number: return "Number :" + x;
case String: return "String : '" + x + "'";
case Date: return "Date :" + x;
case RegExp: return "Regexp :" + x;
case Complex: return "Complex " + x;
}
}
"------------- 构造函数的名称".description();
function classof(o){
if (o === null) return "Null";
if (0 === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8,-1);
}
Object.defineProperty(Function.prototype,"getName",{
writable:true,
enumerable:false,
configurable:true,
value:function(){
if("name" in this) return this.name;
return this.name = this.toString().match(/function\s*([^(]*)\(/)[1];
}
});
function type(o){
var t,c,n;
if(o === null) return "null";
if(o !== o) return "nan";
if((t = typeof o) !== "object") return t;
if((c = classof(o)) !== "Object") return c;
if(o.constructor && typeof o.constructor === "function" && (n = o.constructor.getName()))
return n;
return "Object";
}
type(cmpx).description();
"------------- 鸭式辨型".description();
function quacks(o)
{
for(var i = 1 ; i < arguments.length; i++)
{
var arg = arguments[i];
switch(typeof arg){
case "string":
if(typeof o[arg] !== "function") return false;
continue;
case "function":
arg = arg.prototype;
case "object":
for(var m in arg){
if(typeof arg[m] !== "function") continue;
if(typeof o[m] !== "function") return false;
}
}
}
return true;
}
quacks(cmpx,Object).description();
"=============JavaScript的面向对象技术".description();
"------------- 一个例子:集合类".description();
function Set(){
this.values = {};
this.n = 0;
this.add.apply(this,arguments);
}
Set.prototype.add = function()
{
for(var i = 0; i < arguments.length; i++)
{
var val = arguments[i];
var str = Set._v2s(val);
if(!this.values.hasOwnProperty(str))
{
this.values[str] = val;
this.n++;
}
}
return this;
};
Set.prototype.remove = function()
{
for(var i = 0; i < arguments.length; i++){
var str = Set._v2s(arguments[i]);
if(this.values.hasOwnProperty(str)){
delete this.values[str];
this.n--;
}
}
return this;
}
Set.prototype.contains = function(value){
return this.values.hasOwnProperty(Set._v2s(value));
}
Set.prototype.size = function()
{
return this.n;
}
Set.prototype.foreach = function(fun,context)
{
for(var val in this.values)
{
if (this.values.hasOwnProperty(val)) {
fun.call(context,this.values[val]);
}
}
}
Set._v2s = function (val){
switch(val){
case undefined: return "u";
case null: return "n";
case true: return "t";
case false: return "f";
default:switch(typeof val){
case "number": return "#"+val;
case "string": return '"'+val;
default: return '@'+objectId(val);
}
}
function objectId(o){
var prop = "|**objectid**|";
if(!o.hasOwnProperty(prop))
o[prop] = Set._v2s.next++;
return o[prop];
}
};
Set._v2s.next = 100;
var set = new Set();
set.add("奥特曼");
set.add(12344);
set.add({x:1,y:2});
set.description();
set.remove(12344);
set.description();
"------------- 一个例子:枚举类型".description();
function enumeration(namesToValues)
{
var enumeration = function()
{
throw "Can't Instantiate Enumeration";
}
enumeration.prototype.toString = function(){ return this.name; };
enumeration.prototype.valueOf = function(){return this.value;};
enumeration.prototype.toJSON = function(){return this.name;};
var prop = enumeration.prototype;
enumeration.values = [];
for(name in namesToValues)
{
var e = inherit(prop);
e.name = name;
e.value = namesToValues[name];
enumeration[name] = e;
enumeration.values.push(e);
}
enumeration.foreach = function(fun,context){
for(var i = 0; i < this.values.length;i++){
fun.call(context,this.values[i]);
}
}
return enumeration;
}
var Coin = enumeration({Penny:1,Nickel:5,Dime:10,Quarter:25});
var c = Coin.Dime;
(c instanceof Coin).description();
(c.constructor === Coin).description();
(Coin.Quarter + 3 * Coin.Nickel).description();
(Coin.Dime == 10).description();
(String(Coin.Dime) + ":" + Coin.Dime).description();
function Card(suit,rank){
this.suit = suit;
this.rank = rank;
}
Card.Suit = enumeration({Club:1,Diamonds:2,Hearts:3,Spades:4});
Card.Rank = enumeration({Two:2,Three:3,Four:4,Five:5,Six:6,Seven:7,Eight:8,
Nine:9,Ten:10,Jack:11,Queen:12,King:13,Ace:14});
Card.prototype.toString = function(){
return this.rank.toString() + " of "+ this.suit.toString();
};
Card.prototype.CompareTo = function(that){
if (this.rank > that.rank) return 1;
if (this.rank < that.rank) return -1;
return 0;
}
Card.orderByRank = function(a,b){
return a.compareTo(b);
}
Card.orderBySuit = function(a,b){
if (this.suit > that.suit) return 1;
if (this.suit < that.suit) return -1;
return a.compareTo(b);
}
function Deck()
{
var cards = this.cards = [];
Card.Suit.foreach(function(s){
Card.Rank.foreach(function(r){
cards.push(new Card(s,r));
});
});
}
Deck.prototype.shuffle = function(){
var deck = this.cards;
var len = deck.length;
for(var i = 0; i < len -1; ++i){
var r = Math.floor(Math.random()* (i + 1));
var temp = deck[i];
deck[i] = deck[r];
deck[r] = temp;
}
return this;
}
Deck.prototype.deal = function(n){
if(this.cards.length < n) throw "Out of cards";
return this.cards.splice(-n,n);
}
"创建一副新扑克牌,洗牌并发牌".description();
var deck = (new Deck()).shuffle();
var hand = deck.deal(6);
hand.description();
"------------- 标准转换方法".description();
"---toString()".description();
"---toLocaleString()".description();
"---valueOf()".description();
"---toJSON()".description();
"------------- 比较方法".description();
"------------- 方法借用".description();
var generic = {
toString:function(){
var s = "[";
if(this.constructor && this.constructor.name)
s += this.constructor.name + ": ";
var n = 0;
for(var name in this){
if(!this.hasOwnProperty(name)) continue;
var value = this[name];
if(typeof value === "function") continue;
if(n++) s += ", ";
s += name + "=" + value;
}
return s + "]";
}
}
Deck.prototype.toString = generic.toString;
deck.toString().description();
"------------- 私有状态".description();
function Point(x,y)
{
this.getPointX = function(){return x;};
this.getPointY = function(){return y;};
}
Point.prototype.toString = function(){
return "(" + this.getPointX()+ "," + this.getPointY() + ")";
}
var point = new Point(66,88);
point.toString().description();
"------------- 构造函数的重载和工厂方法".description();
function Set(){
this.values = {};
this.n = 0;
if(arguments.length == 1 && (type(arguments[0]) == "Array"))
this.add.apply(this,arguments[0]);
else if(arguments.length > 0)
this.add.apply(this,arguments);
}
var mset = new Set([1,2,3,4]);
mset.description();
function SetFromArray(a){
Set.apply(this,a);
}
SetFromArray.prototype = Set.prototype;
var s = new SetFromArray([1,2,3]);
s.description();
(s instanceof Set).description();
"=============子类".description();
"------------- 定义子类".description();
function defineSubclass(superclass,constructor,methods,statics)
{
constructor.prototype = inherit(superclass.prototype);
constructor.prototype.constructor = constructor;
if (methods) extend(constructor.prototype,methods);
if (statics) extend(constructor,statics);
return constructor;
}
Function.prototype.extend = function(constructor,methods,statics)
{
return defineSubclass(this,constructor,methods,statics);
}
function A(){
"A constructor".description();
}
A.prototype.printConstructor = function(){
type(this).description();
}
function B(){
"B constructor".description();
}
A.extend(B);
(new B()).printConstructor();
function SingletonSet(member){
this.member = member;
}
SingletonSet.prototype = inherit(Set.prototype);
extend(SingletonSet.prototype,{
constructor:SingletonSet,
add:function(){throw "read-only set";},
size:function(){return 1;},
foreach:function(f,context){f.call(context,this.member);},
contains:function(x){return x === this.member}
});
"------------- 构造函数和方法链".description();
function NonNullSet(){
Set.apply(this,arguments);
}
NonNullSet.prototype = inherit(Set.prototype);
NonNullSet.prototype.constructor = NonNullSet;
NonNullSet.prototype.add = function()
{
for(var i = 0; i < arguments.length; i++)
{
if(arguments[i] == null)
throw new Error("Can't add null or undefined to a NonNullSet");
return Set.prototype.add.apply(this,arguments);
}
}
function filteredSetSubclass(superclass,filter)
{
var constructor = function(){
superclass.apply(this,arguments);
}
constructor.prototype = inherit(superclass.prototype);
constructor.prototype.constructor = constructor;
constructor.prototype.add = function(){
for(var i = 0; i < arguments.length; i++)
{
var v = arguments[i];
if(!filter(v)) throw("value" + v + " rejected by filter");
}
superclass.prototype.add.apply(this,arguments);
};
return constructor;
}
var StringSet = filteredSetSubclass(Set,function(x){return typeof x === "string"});
var strSet = new StringSet("1");
strSet.description();
"------------- 组合 VS 子类".description();
var FilteredSet = Set.extend(
function FilteredSet(set,filter){
this.set = set;
this.filter = filter;
},
{
add:function(){
if(this.filter){
for(var i = 0; i < arguments.length; ++i){
var v = arguments[i];
if(!this.filter(v))
throw new Error("FilteredSet :value " + v + " rejected by filter");
}
}
this.set.add.apply(this.set,arguments);
return this;
},
remove:function(){
this.set.remove.apply(this.set,arguments);
return this;
},
contains:function(v){return this.set.contains(v);},
size:function(){return this.set.size();},
foreach:function(f,c){this.set.foreach(f,c)}
});
var nullSet = new FilteredSet(new Set(),function(x){return x !== null;});
nullSet.add("1234","null");
nullSet.add(undefined);
nullSet.remove("1234");
nullSet.description();
var s = new FilteredSet(new Set(),function(x){return x !== null;});
var t = new FilteredSet(s,function(x){return !(x instanceof Set);});
t.add(1,2,3,4);
t.remove(3);
t.description();
"------------- 类的层次结构和抽象类".description();
function abstractmethod(){throw new Error("abstract method");}
function AbstractSet(){throw new Error("Can't instantiate abstract classes");}
AbstractSet.prototype.contains = abstractmethod;
var NotSet = AbstractSet.extend(
function(set){this.set = set;},
{
contains:function(x){return !this.set.contains(x);},
toString:function(){return "~" + this.set.toString();},
equals:function(that){
return that instanceof NotSet && this.set.equals(that.set);
}
});
var AbstractEnumerableSet = AbstractSet.extend(
function(){throw new Error("Can't instantiate abstract classes");},
{
isEmpty:function(){return this.size == 0;},
toArray:function(){
var a = [];
this.foreach(function(v){a.push(v);});
return a;
},
toString:function(){
var s = "{";
var i = 0;
this.foreach(function(v){
if(i++ > 0) s += ",";
s += v;
});
},
equals:function(that){
if(! (that instanceof AbstractEnumerableSet)) return false;
if(this.size() != that.siz()) return false;
try{
this.foreach(function(v){
if (!that.contains(v)) throw false;});
return true;
}catch(x){
if(x === false) return false;
throw x;
}
}
});
var SingletonSet = AbstractEnumerableSet.extend(
function (member){this.member = member;},
{
contains:function(x){return x === this.member;},
size:function(){return 1;},
foreach:function(fun,context){fun.call(context,this.member);}
});
var AbstractWritableSet = AbstractEnumerableSet.extend(
function(){throw new Error("Can't instantiate abstract classes");},
{
add:abstractmethod,
remove:abstractmethod,
union:function(that){
var self = this;
that.foreach(function(v){self.add(v);});
return this;
},
intersection:function(that){
var self = this;
var removedSet = [];
this.foreach(function(v){
if (!that.contains(v)) removedSet.push(v);
});
removedSet.forEach(function(v){
self.remove(v);
});
return this;
},
difference:function(that){
var self = this;
that.foreach(function(v){self.remove(v);});
return this;
}
});
var ArraySet = AbstractWritableSet.extend(
function(){
this.values = [];
this.add.apply(this,arguments);
},
{
contains:function(v){
return (this.values.indexOf(v) != -1);
},
size:function(){return this.values.length;},
foreach:function(fun,context){
this.values.forEach(fun,context);
},
add:function(){
for(var i = 0; i < arguments.length;++i){
var arg = arguments[i];
if (!this.contains(arg)) this.values.push(arg);
}
return this;
},
remove:function(){
for(var i = 0; i < arguments.length;++i){
var index = this.values.indexOf(arguments[i]);
if(index == -1) continue;
this.values.splice(index,1);
}
return this;
}
});
var arSet = new ArraySet(10,9,8,7,6,5,4);
arSet.add(100,999).description();
arSet.contains(5).description();
arSet.remove(8).description();
arSet.union(new ArraySet(666,888)).description();
arSet.difference(new ArraySet(9,5,114)).description();
arSet.intersection(new ArraySet(10)).description();
"=============ES5中的类".description();
"-------------让属性不可枚举".description();
(function(){
Object.defineProperty(Object.prototype,"objectId",{
get:idGetter,
enumeration:false,
configurable:false
});
function idGetter(){
if(!(idprop in this)){
if(!Object.isExtensible(this)){
throw Error("Can't define for nonextensible objects");
}
Object.defineProperty(this,idprop,{
value:nextid++,
writable:false,
enumerable:false,
configurable:false,
});
}
return this[idprop];
};
var idprop = "|**objectId**|";
var nextid = 1;
}());
"-------------定义不可变的类".description();
function Range2(from,to){
var props ={
from:{value:from,enumerable:false,writable:false,configurable:false},
to:{value:to,enumerable:false,writable:false,configurable:false}
};
if(this instanceof Range2){
"Range2 constructor".description();
Object.defineProperties(this,props);}
else{
"Range2 factory".description();
return Object.create(Range2.prototype,props);}
}
Object.defineProperties(Range2.prototype,{
includes:{
value:function(x){return this.from <= x && x <= this.to;}
},
foreach:{
value:function(f){
for (var x = Math.ceil(this.form);x <= this.to;x++) f(x);
}
},
toString:{
value:function(){return "(" + this.from + "..." + this.to + ")";}
}
});
(Range2(66,88)).from.description();
(new Range2(11,22)).from.description();
var range1 = new Range2(1,3);
range1.includes(2).description();
function freezeProps(o){
var props = (arguments.length == 1) ? Object.getOwnPropertyNames(o)
: Array.prototype.splice.call(arguments,1);
props.forEach(function(value){
if(!Object.getOwnPropertyDescriptor(o,value).configurable) return;
Object.defineProperties(o,value,{writable:false,configurable:false});
});
return o;
}
"-------------封装对象状态".description();
function Range3(from,to){
if (from > to) throw new Error("Range: from must be <= to");
function getFrom(){return from;};
function getTo(){return to;};
function setFrom(f){if(f <= to) from = f;}
function setTo(f){if(t >= from) to = t;}
Object.defineProperties(this,{
from:{get:getFrom,set:setFrom,enumerable:true,configurable:false},
to:{get:getTo,set:setTo,enumerable:true,configurable:false}
});
};
var range3 = new Range3(9,18);
range3.from.description();
"-------------防止类的扩展".description();
"-------------子类和ES5".description();
function StringSet1(){
this.set = Object.create(null);
this.n = 0;
this.add.apply(this,arguments);
}
StringSet1.prototype = Object.create(AbstractWritableSet.prototype,{
constructor:{value:StringSet1},
contains:{value:function(x){return x in this.set;}},
size:{value:function(){return this.n;}},
foreach:{value:function(f,c){Object.keys(this.set).forEach(f,c);}},
add:{
value:function(){
for(var i = 0;i < arguments.length;++i){
if(!(arguments[i] in this.set)){
this.set[arguments[i]] = true;
this.n++;
}
}
return this;
}
},
remove:{
value:function(){
for(var i = 0;i < arguments.length;++i){
if(arguments[i] in this.set){
delete this.set[arguments[i]];
this.n--;
}
}
return this;
}
}
});
var strSet = new StringSet1("123123","55555");
strSet.foreach(function(value){
value.description();
});
"-------------属性描述符".description();
(function namespace(){
function properties(){
var names;
if (arguments.length == 0)
names = Object.getOwnPropertyNames(this);
else if (arguments.length == 1 && Array.isArray(arguments[0]))
names = arguments[0];
else
names = Array.prototype.splice.call(arguments,0);
return new Properties(this,names);
}
Object.defineProperty(Object.prototype,"properties",{
value:properties,
enumerable:false,writable:true,configurable:true,
});
function Properties(o,names){
this.o = o;
this.names = names;
};
Properties.prototype.hide = function(){
var o = this.o;
var hidden = {enumerable:false};
this.names.forEach(function(v){
if(o.hasOwnProperty(v))
Object.defineProperty(o,v,hidden);
});
return this;
};
Properties.prototype.freeze = function(){
var o = this.o;
var frozen = {writable:false,configurable:factory};
this.names.forEach(function(v){
if(o.hasOwnProperty(v))
Object.defineProperty(o,v,frozen);
});
return this;
};
Properties.prototype.descriptors = function(){
var o = this.o;
var desc = {};
this.names.forEach(function(v){
if(o.hasOwnProperty(v)){
desc[v] = Object.getOwnPropertyDescriptor(o,v);
}
});
return desc;
};
Properties.prototype.toString = function(){
var o = this.o;
var lines = this.names.map(nameToString);
return "{ {"+lines.join("}, {") + "}";
function nameToString(n){
var s = "";
var desc = Object.getOwnPropertyDescriptor(o,n);
if(!desc) return "nonexistent " + n + ":undefined";
if(!desc.configurable) s += "permanent ";
if((desc.get && !desc.set) || !desc.writable) s += "readonly ";
if(!desc.enumerable) s += "hidden ";
if(desc.get || desc.set) s += "accessor " + n;
else s += n + ": " + ((typeof desc.value === "function") ? "function" : desc.value);
return s;
}
};
Properties.prototype.properties().hide();
}());
var asd = Object.create(Object.prototype,{
A:{value:11111},
B:{value:22222},
C:{value:"CCC"},
D:{value:[9,8,7,6]}
});
asd.properties().descriptors().description();
asd.properties().toString().description();
"=============模块".description();
"-------------用做命名空间的对象".description();
var sets = {};
"-------------作为私有命名空间的函数".description();
var Set = (function invocation(){
function Set(){
this.values = {};
this.n = o;
thi.add.apply(this,arguments);
}
Set.prototype.contains = function(value){
return this.values.hasOwnProperty(v2s(value));
};
Set.prototype.size = function(){};
Set.prototype.add = function(){};
Set.prototype.remove = function(){};
Set.prototype.foreach = function(){};
function v2s(value){};
function objectId(o){};
var nextId = 1;
return Set;
}());
var PointC = (function(){
function constructor(xx,yy){
"constructor".description();
Object.defineProperties(this,{
x:{
get:function(){
return xx;
},
set:function(v){
xx = v;
}},
y:{
get:function(){
return yy;
},
set:function(v){
yy = v;
}}
});
_pointSum++;
};
constructor.prototype.add = function(that){
this.x += that.x;
this.y += that.y;
};
constructor.prototype.subtract = function(that){
this.x -= that.x;
this.y -= that.y;
};
constructor.prototype.toString = function(){
return "(" + this.x + "," + this.y + ")";
}
constructor.prototype.getRadius = function(){
return getR(this.x,this.y);
}
constructor.getPointSum = function(){
return _pointSum;
}
var _pointSum = 0;
function getR(x,y){
return Math.sqrt(x * x + y * y);
}
return constructor;
}());
var point = new PointC(3,4);
point.add(new PointC(7,9));
point.toString().description();
point.getRadius().description();
var collections;
if(!collections) collections = {};
collections.sets = (function namespace(){
return {
AbstractSet:AbstractSet,
NotSet:NotSet,
};
}());
collections.sets = (new function namespace(){
this.AbstractSet = AbstractSet;
this.NotSet = NotSet;
}());
collections.sets = {};
(function namespace(){
collections.sets.AbstractSet = AbstractSet;
collections.sets.NotSet = NotSet;
}());