JavaScript详细教程(8) - JavaScript中的面向对象

利用JavaScript实现一个集合类

集合(set)是一种数据结构,用以表示非重复值的无序集合,集合的基础方法包括添加值、检测值是否在集合中,以下代码将实现一个通用的set集合类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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;
};
//如何集合包含这个值,则返回true,否则,返回false
Set.prototype.contains = function(value){
return this.values.hasOwnProperty(Set.v2s(value));
};
//返回集合的大小
Set.prototype.size=function(){
return this.n;
}
//遍历集合中的所有元素,在指定的上下文调用f
Set.prototype.foreach = function(f, context){
for(var s in this.values){
if(this.values.hasOwnProperty(s)){
f.call(context, this.values[s])
}
}
};
//这是一个内部函数,用以将任意JavaScript值和唯一的字符串对应起来
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 '@' + obejctId(val);
}
}
//对任意对象来说,都会返回一个字符串
//针对不同的对象,这个函数会返回不同的字符串
//对于同一个对象多次调用,总是返回相同的字符串
//为了做到这一点,它给o创建了一个属性,在ES5中,这个属性是不可枚举且是只读的
function objectId(o){
var prop = "|**obejctId**|";
if(!o.hasOwnProperty(prop))
o[prop] = Set._v2s.next++;
return o[prop];
}
}
Set._v2s.next = 100;

利用JavaScript实现一个枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//这个函数创建一个新的枚举类型,实参对象表示类的每个实例的名字和值
//返回值是一个构造函数,它标识这个新类
//注意,这个构造函数也会抛出异常,不能使用它来创建该类型的新实例
//返回的构造函数包含名/值对的映射表
//包括由值组成的数组,以及一个foreach()迭代器函数
function enumeration(namesToValues){
//这个虚拟的构造函数式返回值
var enumeration = function(){throw "Can't Instantiate Enumerations"}
//枚举值继承自这个对象
var proto = enumeration.prototype = {
constructor: enumeration,
toString: function(){return this.name;},
valueOf: function(){return this.value},
toJSON: function(){return this.name}
};
enumeration.values = [];
for(name in namesToValues){
//这里调用了前面的inherit()函数,该函数会返回一个传入参数类型的对象,该返回对象继承自传入参数类型
var e = inherit(proto);
e.name = name;
e.value = namesToValues[name];
enumeration[name] = e;
enumeration.values.push(e);
}
//一个类方法,用来对类的实例进行迭代
enumeration.foreach = function(f,c){
for(var i=0; i<this.values.length;i++){
f.call(c, this.values[i])
}
}
//返回标识这个新类型的构造函数
return enumeration;
};

接下来利用上面的枚举类来表示一副扑克牌的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function Card(suit, rank){
this.suit = suit;
this.rank = rank;
}
Card.Suit = enumeration({Clubs: 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(a.suit < b.suit) return -1;
if(a.suit > b.suit) return 1;
if(a.rank < b.rank) return -1;
if(a.rank > b.rank) return 1;
return 0;
};
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 = len-1; i > 0; i--){
var r = math.floor(Math.random()*(i+1)),
var temp = deck[i],
var deck[i] = deck[r]
var deck[r] = temp;
}
};

JavaScript中的方法借用

在JavaScript中多个类中的方法可以共用一个单独的函数。比如,Array类通常定义了一些内置方法,如果定义了一个雷,他的实例是类数组的对象,则可以从Array.prototype中将函数复制至所定义的类的原型对象中。如果以经典的面向对象语言的视角来看JavaScript的话,把一个雷的方法用到其他的类中的做法被称为“多重继承”,然后JavaScript并不是经典的面向对象语言,在JavaScript中一般将其称之为“方法借用”

-------------本文到此结束,感谢您的阅读-------------