-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathproto.js
140 lines (120 loc) · 4.11 KB
/
proto.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* global define */
/**
* Uberproto
*
* A base object for ECMAScript 5 style prototypal inheritance.
*
* @see https://github.com/rauschma/proto-js/
* @see http://ejohn.org/blog/simple-javascript-inheritance/
* @see http://uxebu.com/blog/2011/02/23/object-based-inheritance-for-ecmascript-5/
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.Proto = factory();
}
}(this, function () {
var HAS_SYMBOLS = typeof Object.getOwnPropertySymbols === 'function';
function makeSuper (_super, old, name, fn) {
var isFunction = typeof old === 'function';
var newMethod = function () {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but either pointing to the prototype method
// or to the overwritten method
this._super = isFunction ? old : _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
if (isFunction) {
Object.keys(old).forEach(function (name) {
newMethod[name] = old[name];
});
if (HAS_SYMBOLS) {
Object.getOwnPropertySymbols(old).forEach(function (name) {
newMethod[name] = old[name];
});
}
}
return newMethod;
}
return {
/**
* Create a new object using Object.create. The arguments will be
* passed to the new instances init method or to a method name set in
* __init.
*/
create: function () {
var instance = Object.create(this);
var init = typeof instance.__init === 'string' ? instance.__init : 'init';
if (typeof instance[init] === 'function') {
instance[init].apply(instance, arguments);
}
return instance;
},
/**
* Mixin a given set of properties
* @param prop The properties to mix in
* @param obj [optional]
* The object to add the mixin
*/
mixin: function (prop, obj) {
var self = obj || this;
var fnTest = /\b_super\b/;
var _super = Object.getPrototypeOf(self) || self.prototype;
var descriptors = {};
var proto = prop;
var processProperty = function (name) {
var descriptor = Object.getOwnPropertyDescriptor(proto, name);
if (!descriptors[name] && descriptor) {
descriptors[name] = descriptor;
}
};
// Collect all property descriptors
do {
Object.getOwnPropertyNames(proto).forEach(processProperty);
if (HAS_SYMBOLS) {
Object.getOwnPropertySymbols(proto).forEach(processProperty);
}
} while ((proto = Object.getPrototypeOf(proto)) && Object.getPrototypeOf(proto));
var processDescriptor = function (name) {
var descriptor = descriptors[name];
if (typeof descriptor.value === 'function' && fnTest.test(descriptor.value)) {
descriptor.value = makeSuper(_super, self[name], name, descriptor.value);
}
Object.defineProperty(self, name, descriptor);
};
Object.keys(descriptors).forEach(processDescriptor);
if (HAS_SYMBOLS) {
Object.getOwnPropertySymbols(descriptors).forEach(processDescriptor);
}
return self;
},
/**
* Extend the current or a given object with the given property and return the extended object.
* @param prop The properties to extend with
* @param obj [optional] The object to extend from
* @returns The extended object
*/
extend: function (prop, obj) {
return this.mixin(prop, Object.create(obj || this));
},
/**
* Return a callback function with this set to the current or a given context object.
* @param name Name of the method to proxy
* @param args... [optional] Arguments to use for partial application
*/
proxy: function (name) {
var fn = this[name];
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(this);
return fn.bind.apply(fn, args);
}
};
}));