Серия статей:
- Читать один модуль npm в день (1) — имя пользователя
- Читать один модуль npm в день (2) - mem
- Читать один модуль npm в день (3) — mimic-fn
- Чтение одного модуля npm в день (4) — Throttle-debounce
- Читать один модуль npm в день (5) - ee-first
- Читать один модуль npm в день (6) - pify
Поскольку я планирую подробно изучить коа и связанную с ним экологию, модули npm, которые я буду читать в следующем периоде, будут тесно связаны с коа ^_^
введение в одно предложение
Модули, прочитанные сегодня,delegates, в состав которого входят знаменитыеTJВ письменном виде это может помочь нам удобно и быстро использовать шаблоны проектирования.Шаблон делегирования, то есть объект, выставленный внешним слоем, делегирует запрос другим внутренним объектам для обработки.Текущая версия — 1.0.0, а еженедельный объем загрузки — около 3,64 млн.
Применение
delegatesОсновное использование состоит в том, чтобы связать переменные или функции внутреннего объекта с переменными, представленными во внешнем слое, непосредственно черезdelegates
Метод выполняет следующее делегирование.Основные методы делегирования включают в себя:
- геттер: внешний объект может напрямую обращаться к значению внутреннего объекта
- setter: внешний объект может напрямую изменять значение внутреннего объекта
- access: содержит функции геттеров и сеттеров
- метод: внешний объект может напрямую вызывать функцию внутреннего объекта
const delegates = require('./index');
const petShop = {
dog: {
name: '旺财',
age: 1,
sex: '猛汉',
bar() {
console.log('bar!');
}
},
}
// 将内部对象 dog 的属性、函数
// 委托至暴露在外的 petShop 上
delegates(petShop, 'dog')
.getter('name')
.setter('age')
.access('sex')
.method('bar');
// 访问内部对象属性
console.log(petShop.name)
// => '旺财'
// 修改内部对象属性
petShop.age = 2;
console.log(petShop.dog.age)
// => 2
// 同时访问和修改内部对象属性
console.log(petShop.sex)
// => '猛汉'
petShop.sex = '公主';
console.log(petShop.sex);
// => '公主'
// 调用内部对象函数
petShop.bar();
// 'bar!'
В дополнение к описанному выше методу вы также можете добавить к внешним объектам jQuery-подобные функции, а именно:
- Когда функция не передает параметры, получить соответствующее значение
- Когда функция передает параметры, измените соответствующее значение
const delegates = require('./index');
const petShop = {
dog: {
name: '旺财',
},
}
delegates(petShop, 'dog')
.fluent('name');
// 不传参数,获取内部属性
console.log(petShop.name());
// 传参数,修改内部属性
// 还可以链式调用
console.log(
petShop.name('二哈')
.name('蠢二哈')
.name();
);
Изучение исходного кода
инициализация
// 源码 7 - 1
function Delegator(proto, target) {
if (!(this instanceof Delegator)) return new Delegator(proto, target);
this.proto = proto;
this.target = target;
this.methods = [];
this.getters = [];
this.setters = [];
this.fluents = [];
}
this
Методы | геттеры | сеттеры | красуются в объекте — все это массивы, которые используются для записи того, какие свойства и функции делегируются.
Стоит отметить первую строку приведенной выше функции инициализации: ifthis
нетDelegator
экземпляр, затем позвонитеnew Delegator(proto, target)
. Таким образом, вы можете не забыть написать при вызове функции инициализацииnew
Проблема вызвана тем, что в настоящее время следующие два способа записи эквивалентны:
let x = new Delegator(petShop, 'dog')
let x = Delegator(petShop, 'dog')
Кроме того, давайте поговорим о вызовеnew
В основном сделайте следующее:
- внутри конструктора
this
указывает на вновь созданный пустой объект{}
- выполнить тело конструктора
- Если конструктор имеет явное возвращаемое значение, и значение является объектом, он возвращает ссылку на объект.
- Если конструктор не показывает возвращаемое значение или показывает, что возвращаемое значение не является объектом (например, показывает возвращаемое значение 1, «ха-ха» и т. д.), верните это
getter
// 源码 7-2
Delegator.prototype.getter = function(name){
var proto = this.proto;
var target = this.target;
this.getters.push(name);
proto.__defineGetter__(name, function(){
return this[target][name];
});
return this;
};
Ключ в приведенном выше коде заключается в том, что__defineGetter__
Он может добавлять читаемые свойства к существующим объектам, где первый параметр — это имя свойства, второй параметр — функция, а возвращаемое значение — соответствующее значение свойства:
const obj = {};
obj.__defineGetter__('name', () => 'elvin');
console.log(obj.name);
// => 'elvin'
obj.name = '旺财';
console.log(obj.name);
// => 'elvin'
// 我怎么能被改名叫旺财呢!
Следует отметить, что хотя__defineGetter__
Он широко использовался, но больше не рекомендуется, рекомендуется пройтиObject.defineProperty
достичь той же функции или путемget
Аналогичную функцию реализует оператор:
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'elvin',
});
Object.defineProperty(obj, 'sex', {
get() {
return 'male';
}
});
const dog = {
get name() {
return '旺财';
}
};
Кто-то на Github предложил соответствующийPR#20, но поскольку TJ покинул сообщество Node.js, предполагается, что этот репозиторий не будет обновляться.
setter
// 源码 7-3
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
почти идентичны, но с использованием__defineSetter__
, который может добавлять читаемые свойства к существующему объекту, где первый параметр — это имя свойства, второй параметр — функция, а параметр — входящее значение:
const obj = {};
obj.__defineSetter__('name', function(value) {
this._name = value;
});
obj.name = 'elvin';
console.log(obj.name, obj._name);
// undefined 'elvin'
Аналогично, хотя__defineSetter__
Он широко использовался, но больше не рекомендуется, рекомендуется пройтиObject.defineProperty
достичь той же функции или путемset
Аналогичную функцию реализует оператор:
const obj = {};
Object.defineProperty(obj, 'name', {
set(value) {
this._name = value;
}
});
const dog = {
set(value) {
this._name = value;
}
};
method
// 源码 7-4
Delegator.prototype.method = function(name){
var proto = this.proto;
var target = this.target;
this.methods.push(name);
proto[name] = function(){
return this[target][name].apply(this[target], arguments);
};
return this;
};
method
Реализация тоже очень простая, только обратите внимание на вотapply
Первый параметр функции — это внутренний объектthis[target]
, тем самым обеспечивая выполнение функцииthis[target][name]
, тело функцииthis
является указателем на соответствующий внутренний объект.
разноеdelegatesПредусмотрены такие функции, какfluent
| access
Все они похожи и не повторяются.
использовать в коа
В коа его ядро лежит вcontext
объект, многие операции чтения и записи основаны на нем, например:
-
ctx.header Получить заголовок запроса
-
ctx.method Получить метод запроса
-
ctx.url Получить URL запроса
-
...
Получение этих параметров запроса выигрывает от koacontext.request
Многие атрибуты довереныcontext
начальство:
// Koa 源码 lib/context.js
delegate(proto, 'request')
.method('acceptsLanguages')
.method('acceptsEncodings')
.access('path')
.access('url')
.getter('headers')
.getter('ip');
// ...
Другой пример:
- ctx.body устанавливает тело ответа
- ctx.status устанавливает код состояния ответа
- ctx.redirect() запрос перенаправления
- ...
Эти настройки для параметров ответа выигрывают от koacontext.response
Многие свойства и методы довереныcontext
начальство:
// Koa 源码 lib/context.js
delegate(proto, 'response')
.method('redirect')
.method('vary')
.access('status')
.access('body')
.getter('headerSent')
.getter('writable');
// ...
О себе: Окончил Хуаке, работаю в Tencent,блог ЭлвинаДобро пожаловать в гости ^_^