Ответ:
Вы можете сделать это, создав Конструктор , который включает частные методы для сортировки и определяет итератор .
Это будет сводить ваши логики c к:
if ( condition ) {
obj.sort( [ "a", "b", "c" ] );
} else {
obj.sort( [ "a", "c", "b" ] );
}
Пример:
// Constructor
function ObjectSortable( obj ) {
const private = {
sort: function( order ) {
this[ Symbol.iterator ] = function*() {
order = order.map( prop => this[ prop ] );
yield* order;
};
return this;
}
}
let sortable = new Proxy( obj, {
get: function( target, prop, receiver ) {
if ( private[ prop ] ) {
return private[ prop ].bind( sortable );
}
return target[ prop ];
}
} );
sortable.sort( Object.keys( obj ) );
return sortable;
}
// Use
var condition = false,
obj = ObjectSortable( {
"a": 1,
"b": 2,
"c": 3
} );
if ( condition ) {
obj.sort( [ "a", "b", "c" ] );
} else {
obj.sort( [ "a", "c", "b" ] );
}
for(let item of obj) {
console.log(item);
}
Шаги:
Вот шаги, которые мы выполнили для решения проблемы:
- Создание Конструктор , который принимает Объект
- Создание частных методов Объект в замыкании
- Создание
sort
метод, который принимает sort order и определяет новый Symbol.iterator
в context (наш переданный в Object )
- создать прокси для нашего переданного объекта
- создать обработчик get для прокси , Это будет обрабатываться при попытке поиска свойства в нашем Object .
- В течение получить , если имя свойства соответствует приватному методу, bind нашему Объекту как context для нашего частного метода и вызов его.
- вернуть наш Proxy
Если это звучит как много, не волнуйтесь! Я буду go по кусочкам.
Подробное описание конструктора:
Конструктор ObjectSortable
принимает Object
в качестве единственного параметра.
function ObjectSortable( obj ) {...}
Создает объект для частных методов и создает метод sort
, который принимает Array
из ключей в качестве единственного параметра ( order ):
const private = {
sort: function( order ) {
...
}
}
Sort
назначает новый итератор контексту и использует order Array
для получения значений. Затем он возвращает контекст.
sort: function( order ) {
this[ Symbol.iterator ] = function*() {
order = order.map( prop => this[ prop ] );
yield* order;
};
return this;
}
Мы создаем Proxy
с именем sortable и предоставляем наш обработчик Object
и get :
let sortable = new Proxy( obj, {
get: function( target, prop, receiver ) {
...
}
});
В обработчике get мы добавляем условие, которое говорит, что , если имя свойства, которое мы ищем, является методом нашего частного объекта , мы привязываем Object к этому методу и вызываем его.
Ae Если мы получаем Object["a"]
, это дает нам Object["a"]
, но если мы пытаемся получить Object["sort"]
, это дает нам private.sort.bind(Object)
Примечание: это закрытие делает наши методы приватными :
let sortable = new Proxy( obj, {
get: function( target, prop, receiver ) {
if ( private[ prop ] ) {
return private[ prop ].bind( sortable );
}
return target[ prop ];
}
});
Наконец мы вызываем нашу sort
функцию наш Proxy
для установки нашего итератора по умолчанию, так как прототипы объектов не имеют его изначально:
sortable.sort( Object.keys( obj ) );
и возвращают прокси:
return sortable;
Объяснение в глубину использования:
Поскольку у нас есть Конструктор , который принимает Object
, мы можем обернуть наш определенный объект при его инициализации:
obj = ObjectSortable( {
"a": 1,
"b": 2,
"c": 3
});
Затем мы применяем наш Кондит ional logi c с использованием нашей функции sort
:
if ( condition ) {
obj.sort( [ "a", "b", "c" ] );
} else {
obj.sort( [ "a", "c", "b" ] );
}
Наконец, мы перебираем элементы , которые находятся в правильном порядке:
for(let item of obj) {
console.log(item);
}
Внутренние элементы Symbol.iterator
позволяют нам легко вычислять l oop по результатам, используя for...of
l oop, но мы также можем помещать их в массив при необходимости, используя оператор распространения:
let orderedArray = [...obj];
Из приведенного выше принуждения мы можем l oop использовать Array
методы, такие как forEach
, map
, reduce
, et c.
Лично я рекомендовал бы создать свой собственный метод итерации
Как добавить forEach
:
Поскольку мы уже используем конструктор , определяющий наш собственный итератор и предоставление частных методов, , мы можем очень легко расширить private
с помощью метода forEach
.
const private = {
forEach: function(fn) {
for (let value of this) {
fn(value);
}
},
sort: function(order) {
...
}
}
Наш метод forEach
принимает Function
как единственный параметр. Затем функция вызывается для каждого значения , предоставленного итератором .
Отличительной особенностью в вышеприведенном является то, что из-за нашей динамической привязки c в нашем обработчике get , мы можем просто сказать forEach
методу итерировать по текущий контекст.
Это приведет к меньшему коду по сравнению с for...of
l oop или Принуждению массива и его легче поддерживать с функциональной точки зрения.
для каждого примера:
function ObjectSortable(obj = {}) {
const private = {
forEach: function(fn) {
for (let value of this) {
fn(value);
}
},
sort: function(order) {
this[Symbol.iterator] = function*() {
order = order.map(prop => this[prop]);
yield* order;
};
return this;
}
}
let sortable = new Proxy(obj, {
get: function(target, prop, receiver) {
if (private[prop]) {
return private[prop].bind(sortable);
}
return target[prop];
}
});
sortable.sort(Object.keys(obj));
return sortable;
}
let test = ObjectSortable();
test.a = "world";
test.b = "hello";
test.sort(["b","a"]);
test.forEach(console.log)
forEach в вашей демоверсии:
function ObjectSortable(obj = {}) {
const private = {
forEach: function(fn) {
for (let value of this) {
fn(value);
}
},
sort: function(order) {
this[Symbol.iterator] = function*() {
order = order.map(prop => this[prop]);
yield* order;
};
return this;
}
}
let sortable = new Proxy(obj, {
get: function(target, prop, receiver) {
if (private[prop]) {
return private[prop].bind(sortable);
}
return target[prop];
}
});
sortable.sort(Object.keys(obj));
return sortable;
}
var condition = false,
obj = ObjectSortable( {
"a": 1,
"b": 2,
"c": 3
} );
if ( condition ) {
obj.sort( [ "a", "b", "c" ] );
} else {
obj.sort( [ "a", "c", "b" ] );
}
obj.forEach(console.log);
Заключение:
Надеюсь, это дало вам представление о некоторых внутренних элементах JavaScript объектов и о том, как вещи могут соединяться друг с другом, используя вещи как шаблон частного метода. Я надеюсь, что это решит вашу проблему!
Счастливого кодирования!