-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
124 lines (101 loc) · 3.76 KB
/
main.js
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
// Sentinel value passed to base constructors to skip invoking this.init.
var populating = {};
function makeClass(base, newProps) {
var baseProto = base.prototype;
var ownProto = Object.create(baseProto);
var newStatics = newProps.statics;
var populated;
function constructor() {
if (!populated) {
if (base.extend === extend) {
// Ensure population of baseProto if base created by makeClass.
base.call(populating);
}
// Wrap override methods to make this._super available.
populate(ownProto, newProps, baseProto);
// Help the garbage collector reclaim this object, since we
// don't need it anymore.
newProps = null;
populated = true;
}
// When we invoke a constructor just for the sake of making sure
// its prototype has been populated, the receiver object (this)
// will be strictly equal to the populating object, which means we
// want to avoid invoking this.init.
if (this === populating) {
return;
}
// Evaluate this.init only once to avoid looking up .init in the
// prototype chain twice.
var init = this.init;
if (init) {
init.apply(this, arguments);
}
}
// Copy any static properties that have been assigned to the base
// class over to the subclass.
populate(constructor, base);
if (newStatics) {
// Remove the statics property from newProps so that it does not
// get copied to the prototype.
delete newProps.statics;
// We re-use populate for static properties, so static methods
// have the same access to this._super that normal methods have.
populate(constructor, newStatics, base);
// Help the GC reclaim this object.
newStatics = null;
}
// These property assignments overwrite any properties of the same
// name that may have been copied from base, above. Note that ownProto
// has not been populated with any methods or properties, yet, because
// we postpone that work until the subclass is instantiated for the
// first time. Also note that we share a single implementation of
// extend between all classes.
constructor.prototype = ownProto;
constructor.extend = extend;
constructor.base = baseProto;
// Setting constructor.prototype.constructor = constructor is
// important so that instanceof works properly in all browsers.
ownProto.constructor = constructor;
// Setting .cls as a shorthand for .constructor is purely a
// convenience to make calling static methods easier.
ownProto.cls = constructor;
// If there is a static initializer, call it now. This needs to happen
// last so that the constructor is ready to be used if, for example,
// constructor.init needs to create an instance of the new class.
if (constructor.init) {
constructor.init(constructor);
}
return constructor;
}
function populate(target, source, parent) {
for (var name in source) {
if (source.hasOwnProperty(name)) {
target[name] = parent ? maybeWrap(name, source, parent) : source[name];
}
}
}
var hasOwnExp = /\bhasOwnProperty\b/;
var superExp = hasOwnExp.test(populate) ? /\b_super\b/ : /.*/;
function maybeWrap(name, child, parent) {
var cval = child && child[name];
var pval = parent && parent[name];
if (typeof cval === "function" &&
typeof pval === "function" &&
cval !== pval && // Avoid infinite recursion.
cval.extend !== extend && // Don't wrap classes.
superExp.test(cval)) // Only wrap if this._super needed.
{
return function() {
var saved = this._super;
this._super = parent[name];
try { return cval.apply(this, arguments) }
finally { this._super = saved };
};
}
return cval;
}
function extend(newProps) {
return makeClass(this, newProps || {});
}
module.exports = extend.call(function(){});