forked from HCThink/h-blog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
184 lines (157 loc) · 4.26 KB
/
index.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**
* Expose `Delegator`.
*/
module.exports = Delegator;
/**
* Initialize a delegator.
*
* @param {Object} proto
* @param {String} target
* @api public
*/
function Delegator(proto, target) {
// 兼容调用方式,常见做法, 可以参考 new.targer
if (!(this instanceof Delegator)) return new Delegator(proto, target);
this.proto = proto;
this.target = target;
// api 配备 list, 仅用于记录
this.methods = [];
this.getters = [];
this.setters = [];
this.fluents = [];
}
// ------------------------ api ------------------------
/**
* Automatically delegate properties
* from a target prototype
*
* @param {Object} proto
* @param {object} targetProto
* @param {String} targetProp
* @api public
*/
Delegator.auto = function (proto, targetProto, targetProp) {
debugger;
// 调用主入口, 委托 targetProp 到 proto
var delegator = Delegator(proto, targetProp);
// 循环处理每个属性:targetProto's properties, 依次按照规则委托到 proto
var properties = Object.getOwnPropertyNames(targetProto);
for (var i = 0; i < properties.length; i++) {
var property = properties[i];
var descriptor = Object.getOwnPropertyDescriptor(targetProto, property);
if (descriptor.get) {
delegator.getter(property);
}
if (descriptor.set) {
delegator.setter(property);
}
// 依据类型依次代理。
if (descriptor.hasOwnProperty('value')) { // could be undefined but writable
var value = descriptor.value;
if (value instanceof Function) {
delegator.method(property);
} else {
delegator.getter(property);
}
// 这里优点奇怪,如果 targetProto 有函数成员,此时委托会将 delegator.method(property); 覆盖变为 : c: [Setter]。
// 不是很明吧这里的用意
if (descriptor.writable) {
delegator.setter(property);
}
}
}
};
/**
* Delegate method `name`.
*
* @param {String} name
* @return {Delegator} self
* @api public
*/
Delegator.prototype.method = function (name) {
var proto = this.proto;
var target = this.target;
// 仅用于记录,并且没有去重。
this.methods.push(name);
// 执行器
proto[name] = function () {
// 维护委托操作中的 this 指向, 以保证其正常执行
return this[target][name].apply(this[target], arguments);
};
// 链式
return this;
};
/**
* Delegator accessor `name`.
*
* @param {String} name
* @return {Delegator} self
* @api public
*/
Delegator.prototype.access = function (name) {
return this.getter(name).setter(name);
};
/**
* Delegator getter `name`.
*
* @param {String} name
* @return {Delegator} self
* @api public
*/
Delegator.prototype.getter = function (name) {
var proto = this.proto;
var target = this.target;
this.getters.push(name);
// __defineGetter__: 方法可以将一个函数绑定在当前对象的指定属性上,当那个属性的值被读取时,你所绑定的函数就会被调用。
// 该特性是非标准的,请尽量不要在生产环境中使用它!
// 该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。
/**
* 参考: Object.defineProperty api 可以改造。
Object.defineProperty(proto, name, {
get() {
return this[target][name];
}
});
*/
proto.__defineGetter__(name, function () {
return this[target][name];
});
return this;
};
/**
* Delegator setter `name`.
*
* @param {String} name
* @return {Delegator} self
* @api public
*/
Delegator.prototype.setter = function (name) {
var proto = this.proto;
var target = this.target;
this.setters.push(name);
proto.__defineSetter__(name, function (val) {
return this[target][name] = val;
});
return this;
};
/**
* Delegator fluent accessor
*
* @param {String} name
* @return {Delegator} self
* @api public
*/
Delegator.prototype.fluent = function (name) {
var proto = this.proto;
var target = this.target;
this.fluents.push(name);
proto[name] = function (val) {
if ('undefined' != typeof val) {
this[target][name] = val;
return this;
} else {
return this[target][name];
}
};
return this;
};