Внезапно, разве метод Ruby не удобен? При написании кода он перечисляет все методы и свойства, доступные для объекта, и позволяет осуществлять поиск по ним, что очень полезно при отладке.
Кроме того, он также эффективен для проверки методов, специфичных для таких фреймворков, как Rails, помогая читать код и понимать библиотеки. Хотя хорошей практикой является обращение к официальной документации или исходному коду, метод методы весьма полезен для библиотек, в которых вам не нужно глубоко погружаться или когда у вас смутные воспоминания об именах методов.
Если кратко представить метод методов Ruby, он выглядит так:
Объект#метод
Возвращает список имен общедоступных и защищенных методов объекта. Сюда будут включены все методы, доступные в предках obj. Если необязательный параметр имеет значение false, он возвращает массив общедоступных и защищенных одноэлементных методов obj, массив не будет включать методы в модулях, включенных в obj.
Другими словами, он возвращает объект массива свойств и методов, доступных из получателя.
Этот метод реализован в классе Object, который является предком всех классов, наследуемых от Object, поэтому его можно использовать в любом классе, наследующем от Object.
Пример кода
class Hoge attr_accessor :fuga def bar puts '' end end puts Hoge.new.methods // => [:bar, :fuga=, :fuga, :hash, :singleton_class, :dup, ...] puts Hoge.new.grep /fuga/ // => [:fuga=, :fuga]
Как показано в примере, он возвращает объект Array, поэтому вы также можете выполнять поиск по списку методов с помощью метода grep, что очень удобно.
Итак, я подумал, можно ли это сделать на JS, и попробовал.
Ниже приведен фактический код.
Имя класса может быть любым, но я пока называю его PropertyFinder.
class PropertyFinder { constructor(receiver) { this.receiver = receiver } grep(regexp, options = {}) { let res = [] if (typeof regexp === 'string') { return this.find((name) => name.includes(regexp)) } if (regexp instanceof RegExp) { return this.find((name) => regexp.test(name)) } return [] } toString() { return this.find(() => true) } find(detect) { const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it)) if (!this.receiver.__proto__) { return list } const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect) return [...list, ...ancestors] } }
Я объясню код позже, но давайте начнем с того, как его использовать.
После определения класса вы можете добавить метод к свойствам класса Object следующим образом:
Object.prototype.methods = function () { return new PropertyFinder(this) }
Сделав это, вы сможете использовать метод методов для экземпляров классов, наследуемых от Object. Однако обратите внимание на предостережение ниже и используйте его на свой страх и риск.
Вот несколько примеров выполнения:
class Hoge { fuga() { console.log('fuga') } } console.log(new Object().methods().toString()) // => ['constructor', 'constructor', '__defineGetter__', '__defineSetter__', 'hasOwnProperty' ...] console.log([].methods().toString()) // => ['length', 'length', 'constructor', 'at', 'concat', ...] console.log(new Hoge().methods().grep(/fuga/) // => ['fuga']
*Этот код не рекомендуется использовать в производственных средах *
Добавление свойств в классы более высокого уровня с помощью обезьяньего исправления является антишаблоном и может привести к проблемам с будущими изменениями в спецификациях JS. Используйте его с осторожностью и на свой страх и риск.
Ссылка: минусы обезьяньего патча
Теперь перейдем к объяснению кода.
Самый важный метод в PropertyFinder — метод find. Этот метод обходит цепочку прототипов данного объекта, ищет доступные свойства и возвращает их в виде списка.
Методы toString и grep просто используют find, поэтому в дальнейших пояснениях они не нуждаются.
Цепочка прототипов может быть кому-то незнакома, но это наследование свойств из класса Object.
Наследование и цепочка прототипов | МДН
Подробности описаны в документации MDN, но механизм наследования JavaScript поддерживается цепочкой прототипов.
Хотя это не всегда очевидно, при упоминании какого-либо свойства процесс включает в себя:
Этот процесс продолжается вверх по цепочке до тех пор, пока не будет найдено совпадение, которое затем возвращается.
Учитывая вышеизложенное, метод find в PropertyFinder реализует этот механизм, позволяющий получить список свойств путем рекурсивного изучения __proto__.
Вот реализация, которая достигает этого путем рекурсивного изучения __proto__ для получения списка:
find(detect) { const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it)) if (!this.receiver.__proto__) { return list } const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect) return [...list, ...ancestors] }
На этом объяснение PropertyFinder завершается.
На этом объяснение кода и того, что я пробовал, закончено.
Это было скорее экспериментальное или игровое упражнение, но, поскольку оно требовало некоторых знаний и методов, я надеюсь, что вы найдете его полезным или вдохновляющим для ваших собственных приложений.
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3