-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmyClass.html
More file actions
159 lines (140 loc) · 7.79 KB
/
myClass.html
File metadata and controls
159 lines (140 loc) · 7.79 KB
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
/*
* original: https://gist.github.com/shakyShane/5944153 John Resig's Posting
*/
// call a immediate funciton,prevent global namespace from being polluted.
(function(){
// 这个initializing变量用于标识当前是否处于类的初始创建阶段,下面会继续详述
var initializing = false,
// 这是一个技巧性的写法,用于检测当前环境下函数是否能够序列化
// 附一篇讨论函数序列化的文章:http://www.cnblogs.com/ziyunfei/archive/2012/12/04/2799603.html
// superPattern引用一个正则对象,该对象用于验证被验证函数中是否有使用_super方法
superPattern = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
var Class = function (){};
window.Class = Class;
Class.extend = function(properties){
var oStatics = properties.statics,oMembers = properties.members;
// 当前对象(父类)的原型对象
var _super = this.prototype;
properties.init && (oMembers.init = properties.init);
// initializing = true表示当前处于类的初始创建阶段。
// this构造函数里会判断initializing的状态,如果为false则不执行Init方法。
// 事实上这也是非常需要的,因为在这个时候,我们需要的只是一个干净的虚构的构造函数,完全不需要其执行init函数,以避免污染。init方法只有在当前类被实例化的时候才需要被执行,而当前正执行继承行为,不应该执行Init方法。
initializing = true;
// 当前对象(父类)的一个实例对象
var proto = new this();
// 初始创建阶段完成,置initializing为false
initializing = false;
// 在properties里提供的成员,作为当前对象(父类)实例的公共成员,供其子类实例共享;
for(var name in oMembers){
proto[name] = typeof oMembers[name] == 'function' && //检测当前提供的是否为函数
typeof _super[name] == 'function' && //检测当前提供的函数名是否已经存在于父类的原型对象中,如果是,则需要下面的操作,以保证父类中的方法不会被覆盖且可以以某种方式被调用,如果否,则直接将该函数赋值为父类实例的方法
superPattern.test(oMembers[name]) ? //检测当前提供的函数内是否使用了_super方法,如果有使用_super方法,则需要下面的操作,以保证父类中的方法不会被覆盖且可以以某种方式被调用,如果没有用到_super方法,则直接将该函数赋值为父类实例的方法,即使父类原型中已经拥有同名方法(覆盖)
// 使用一个函数,返回一个闭包,这样每个闭包引用的都是各自的name和fn。
getSuper(name, oMembers[name]) :
oMembers[name];
}
function getSuper(name, fn){
return function() {
// 首先将执行方法的当前对象(子类的实例化对象)的_super属性保存到tmp变量里。
// 这是非常必要的, 因为this永远指向当前正在被调用的对象。
// 当C继承B,B继承A,而A\B\C均有一个dance方法且B\C的dance方法均使用了this._super来引用各自父类的方法时,下面这句操作就显得非常重要了。它使得在方法调用时,this._super永远指向“当前类”的父类的原型中的同名方法,从而避免this._super被随便改写。
var tmp = this._super || {};
// 然后将父类的原型中的同名方法赋值给this._super,以便子类的实例化对象可以在其执行name方法时通过this._super使用对应的父类原型中已经存在的方法
this._super = _super[name];
// 执行创建子类时提供的函数,并通过arguments传入参数
var ret = fn.apply(this, arguments);
// 将tmp里保存的_super属性重新赋值回this._super中
this._super = tmp;
// 返回函数的执行结果
return ret;
};
}
// 内部定义个名叫Class的类,构造函数内部只有一个操作:执行当前对象中可能存在的init方法
// 这样做的原因:新建一个类(闭包),可以防止很多干扰(详细可对比JS高级设计第三版)
function SubClass(){
// 如果不是正在实现继承,并且当前类的init方法存在,则执行init方法
// 每当subClass方法执行完毕后,都会返回这个Class构造函数,当用户使用new 方法时,就会执行这里面的操作
// 本质:每次调用subClass都新建一个类(闭包)
if(!initializing && this.init){
// 这是子类的初始化方法,里面可以定义子类的私有属性,公共属性请在上方所述处添加
this.init = typeof this.init == 'function' &&
typeof _super['init'] == 'function' &&
superPattern.test(oMembers[name]) ?
getSuper('init', this.init) :
this.init;
this.init.apply(this, arguments);
}
}
// 添加静态成员
for(var sProp in oStatics){
SubClass[sProp] = oStatics[sProp];
}
// 重写Class构造函数的prototype,使其不再指向了Class原生的原型对象,而是指向了proto,即当前对象(类)的一个实例
// 本质:一个类的原型是另一个类的实例(继承)
SubClass.prototype = proto;
// 为什么要重写Class的构造函数?因为这个Class函数,它原来的constructor指向的是Function对象,这里修正它的指向,使其指向自己。
proto.constructor = SubClass;
// 就是这个操作,使得每次调用subClass都会新生命的Class对象,也拥有subClass方法,可以继续被继承下去
// 本质:使得每次继承的子类都拥有被继承的能力
SubClass.extend = arguments.callee;
// 返回这个内部新定义的构造函数(闭包)
return SubClass;
};
})();
var Person = Class.extend({
init: function(isDancing) {
this.dancing = isDancing;
},
statics: {
STATIC: 'static',
NO: 1
},
members:{
dance: function(){
console.log('i am a person,i dance.');
return this.dancing;
}
}
});
var Ninja = Person.extend({
init:function(){
this._super(arguments[0]);
},
members:{
dance: function() {
console.log('i am an Ninja,i dance.');
this._super();
return;
},
swingSword:function(){
return true;
}
}
});
var Chileung = Ninja.extend({
members:{
dance: function(){
console.log('i am Chileung.i dance.');
this._super();
return;
}
}
});
var p = new Person('person dancing');
p.dance();
var n = new Ninja('ninja dancing');
n.dance();
console.log(n);
var c = new Chileung();
c.dance();
</script>
</body>
</html>