node-delegates源码解析

介绍

Node 方法和访问器委托实用程序。

delegates 官方如此介绍,实际上用于委托模式的实现。

demo

1
2
3
4
5
6
7
8
delegate(proto, "request")
.method("acceptsLanguages")
.method("acceptsEncodings")
.method("is")
.access("querystring")
.access("url")
.getter("subdomains")
.getter("protocol");

源码 delegates 1.0.0

delegator 函数

1
2
3
4
5
6
7
8
9
10
11
function Delegator(proto, target) {
// 判断当前是调用Delegator内的函数还是初始化实例
if (!(this instanceof Delegator)) return new Delegator(proto, target);
// 将对象分别设置到this,初始化数组保存
this.proto = proto;
this.target = target;
this.methods = [];
this.getters = [];
this.setters = [];
this.fluents = [];
}

method 函数

1
2
3
4
5
6
7
8
9
10
11
12
Delegator.prototype.method = function (name) {
var proto = this.proto;
var target = this.target;
// 函数名push到methods中保存
this.methods.push(name);

proto[name] = function () {
return this[target][name].apply(this[target], arguments);
};

return this;
};

proto[name]实际返回的是 target[name]函数的调用,也就是说使 proto 可以调用 target 上的函数,apply 则保证调用时作用域是在 target 内,保证内部指向正确。

getter 函数

1
2
3
4
5
6
7
8
9
10
11
12
Delegator.prototype.getter = function (name) {
var proto = this.proto;
var target = this.target;
// 将属性名保存到getters中
this.getters.push(name);

proto.__defineGetter__(name, function () {
return this[target][name];
});

return this;
};

setter 函数

1
2
3
4
5
6
7
8
9
10
11
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;
};

getter 和 setter 则是分别使用__defineGetter____defineSetter__劫持 proto 的 get 和 set,实际调用的也是 target 上的内容。现在官方更推荐Object.definePropertyProxy

这是 MDN 的描述,值得一提这是非标准且已废弃的属性。

**__defineGetter__ **方法可以将一个函数绑定在当前对象的指定属性上,当那个属性的值被读取时,你所绑定的函数就会被调用。

access 函数

1
2
3
Delegator.prototype.access = function (name) {
return this.getter(name).setter(name);
};

该函数与 getter 和 setter 同理,因返回 this 可以使用链式调用。

auto 函数

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
Delegator.auto = function (proto, targetProto, targetProp) {
// 直接调用Delegator函数,将对象设置到this上
var delegator = Delegator(proto, targetProp);
// 获取目标对象上的属性,并遍历
var properties = Object.getOwnPropertyNames(targetProto);
for (var i = 0; i < properties.length; i++) {
var property = properties[i];
// property属性存在于targetProto对象上,则返回其属性描述符对象
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;
// 获取并判断value的类型,分别调用
if (value instanceof Function) {
delegator.method(property);
} else {
delegator.getter(property);
}
// 判断是可写类型则设置setter
if (descriptor.writable) {
delegator.setter(property);
}
}
}
};

auto 函数主要由函数判断、遍历对象的属性,使用哪种方法。其中 getOwnPropertyDescriptor 方法:

Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

示例 demo
1
2
3
4
5
6
7
const object1 = {
property1: 42,
};
const descriptor1 = Object.getOwnPropertyDescriptor(object1, "property1");
// 属性描述符对象结构
// {value: 42, writable: true, enumerable: true, configurable: true}
console.log(descriptor1);

fluent 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
};

proto[name]设置为一个函数,传入非空值时设置到 target[name],否则获取 target[name]的值。

参考链接:

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

给阿姨来一杯卡普基诺~

支付宝
微信