В последнее время я читаю книгу "Изучение шаблонов JavaScript". То, что я не получаю, - это различие между шаблоном модуля и раскрытием шаблона модуля. Я чувствую, что они одно и то же. Любой может привести пример?
Дизайн шаблона JavaScript: разница между шаблоном модуля и раскрытием шаблона модуля?
Ответ 1
Существует не менее трех различных способов реализации шаблона модуля, но шаблон раскрывающегося модуля является единственным потомком модуля, который имеет официальное имя.
Шаблон базового модуля
Шаблон модуля должен удовлетворять следующему:
- Частные члены живут в закрытии.
- Открытые элементы отображаются в возвращаемом объекте.
Но в этом определении много неопределенности. Устраняя двусмысленность по-разному, вы получаете варианты шаблона модуля.
Шаблон раскрывающего модуля
Шаблон раскрывающегося модуля - самый известный и самый популярный из вариантов модуля. Он имеет ряд преимуществ по сравнению с другими альтернативами, такими как
- Переименовать публичные функции без изменения тела функции.
- Изменение членов от общего доступа к частному или наоборот путем изменения одной строки без изменения тела функции.
RMP удовлетворяет трем дополнительным условиям в дополнение к оригиналу:
- Все члены, будь то публичные или частные, определяются в закрытии.
- Возвращаемый объект является литералом объекта без определения функций. Все правые выражения являются замыкающими переменными
- Все ссылки связаны с переменными замыкания, а не с объектом возврата.
В следующем примере показано, как он используется
var welcomeModule = (function(){
var name = "John";
var hello = function(){ console.log("Hello, " + name + "!");}
var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return {
name: name,
sayHello: hello,
sayWelcome: welcome
}
})();
Если вы хотите сделать private name
и sayHello
частным, вам просто нужно прокомментировать соответствующие строки в возвращаемом объекте.
var welcomeModule = (function(){
var name = "John";
var hello = function(){ console.log("Hello, " + name + "!");}
var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return {
//name: name,
//sayHello: hello,
sayWelcome: welcome
}
})();
Шаблон модуля с условным литералом
Это, вероятно, самый старый вариант шаблона модуля. В отличие от RMP, нет никакого официального официального названия для этого варианта.
В дополнение к оригиналу оно удовлетворяет следующим условиям:
- Частные члены определены в закрытии.
- Открытые элементы определяются в литерале возвращаемого объекта.
- Ссылки на публичных пользователей доступны по
this
, когда это возможно.
В следующем примере вы можете увидеть, как, в отличие от RMP, определения функций фактически находятся в литеральном объекте return, а ссылки на члены - this
.
var welcomeModule = (function(){
return {
name: "John",
sayHello: function(){ console.log("Hello, " + this.name + "!");}
sayWelcome: function() { console.log( this.hello() + " Welcome to StackOverflow!");}
}
})();
Обратите внимание, что разблокировать RMP, чтобы сделать name
и sayHello
private, ссылки, указывающие на name
и sayHello
в различных определениях тела функции, также должны быть изменены.
var welcomeModule = (function(){
var name: "John";
var sayHello = function(){ console.log("Hello, " + name + "!");};
return {
//name: "John",
//sayHello: function(){ console.log("Hello, " + this.name + "!");}
sayWelcome: function() { console.log( hello() + " Welcome to StackOverflow!");}
}
})();
Шаблон модуля с заглушкой объекта возврата
Этот вариант также не имеет официального имени.
В дополнение к оригиналу оно удовлетворяет следующим условиям:
- Пустой пустой объект возвращается в начале.
- Частные члены определены в закрытии.
- Публичные члены определяются как члены заглушки
- Ссылки на публичные элементы через объект-заглушку
Используя наш старый пример, вы можете увидеть, что публичные элементы напрямую добавляются в объект-заглушку.
var welcomeModule = (function(){
var stub = {};
stub.name = "John";
stub.sayHello = function(){ console.log("Hello, " + stub.name + "!");}
stub.sayWelcome = function() { console.log( stub.hello() + " Welcome to StackOverflow!");}
return stub;
})();
Если вы хотите сделать private name
и sayHello
приватным, как и раньше, ссылки на члены теперь-private должны быть изменены.
var welcomeModule = (function(){
var stub = {};
var name = "John";
var sayHello = function(){ console.log("Hello, " + name + "!");}
stub.sayWelcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return stub;
})();
Резюме
Различия между шаблоном раскрывающегося модуля и другими вариантами шаблона модуля в основном связаны с тем, как ссылаются публичные члены. В результате RMP намного проще в использовании и модификации, что объясняет его популярность. Однако эти преимущества приносят огромную цену (на мой взгляд), о чем упоминает адди Османи в своем посте в раскрытии шаблона модуля,
Недостатком этого шаблона является то, что если частная функция относится к публичной функции, эта публичная функция не может быть переопределена, если требуется патч. Это связано с тем, что частная функция будет продолжать ссылаться на частную реализацию, и шаблон не применяется к публичным членам, а только к функциям.
Элементы общедоступных объектов, которые ссылаются на частные переменные, также подчиняются заметкам о правилах без исправлений выше.
В результате этого модули, созданные с помощью шаблона Revealing Module, могут быть более хрупкими, чем те, которые были созданы с использованием исходного шаблона модуля, поэтому следует соблюдать осторожность во время использования.
и о котором я говорил в некоторых других сообщениях.
Ответ 2
Просто попробуйте сделать что-то на основе ответа на верхний комментарий. Может быть, это безопаснее, если вы вызываете частную функцию, передавая это ему, поэтому частная функция может ссылаться на публичную функцию с этой переменной.
Я создал раскрывающий модуль с последующим кодом.
var HTMLChanger = (function () {
var privateFunc = function () {
this.sayHello();
}
var hello = function () {
console.log('say Hello');
}
var callPrivate = function () {
privateFunc.call(this);
}
return {
sayHello: hello,
callPrivate: callPrivate
};
})();
HTMLChanger.callPrivate();
//say Hello
HTMLChanger.sayHello = function() { console.log('say Hi!') };
HTMLChanger.callPrivate();
//say Hi!
Как вы можете видеть, мы можем переопределить открытый элемент.
Ответ 3
Краткий ответ. В модуле модуля мы определяем функции в возвращаемом объекте.
В шаблоне Revealing Module мы определяем функции в области закрытия и используем только имена переменных в возвращаемом объекте.
Это упрощает код и имеет множество других преимуществ