JS: внедрить в BoundFunctionObject для сценария букмарклета

Предположим, я пишу сценарий букмарклета для изменения веб-страницы. Большинство веб-сайтов (использующих веб-пакет и т. д.) имеют примерно такую ​​структуру:

<html>
    <script type = "text/javascript">
        const buttonClicked = (() => {
            let internal_variable = 0;
            const _internal_buttonClicked = () => {
                internal_variable++;
                document.getElementById("myButton").innerText = `Clicked ${internal_variable} times!`;
            };
            return _internal_buttonClicked.bind(this);
        })();
    </script>
    <body>
        <button id = "myButton" onclick = "buttonClicked()">Clicked 0 times!</button>
    </body>
</html>

Я хотел бы получить доступ к internal_variable и установить для него значение -100. С отладчиком это просто; Я делаю точку останова внутри _internal_buttonClicked(), а затем меняю internal_variable напрямую.

Как я могу сделать это без

  • (вручную) с помощью отладчика
  • владение исходным кодом страницы (например, я могу вносить в него изменения локально, но не могу просто отправить запрос на включение, чтобы добавить перехватчик в скрипт)
  • сделать это чисто визуальным изменением DOM?

Я знаю, что простой ответ — «вы не можете намеренно», но я готов принять любые обходные решения, решения, включающие расширения браузера/привилегированное выполнение, решения, специфичные для require и т. д.

Связанный:

  • Как получить параметры, которые были связаны функцией JavaScript .bind()
  • Можно ли получить доступ к закрытию функции? (лучшее решение здесь зависит от того, будет ли скрипт загружаться первым, что часто невозможно для букмарклета? Есть ли способ заставить страницу перезагрузиться и вставить скрипт в верхнюю часть обновленной страницы?)

Это невозможно.

Ry- 25.06.2024 00:18

Я поощряю это, хотя знаю, что хорошего решения может и не быть. Я чувствую, что есть много качественных ответов о том, как отлаживать, исправлять или изменять двоичный файл, и не так уж много информации о том, как сделать то же самое с JS, и я надеюсь узнать, как подойти к этому чрезвычайно -Общая ситуация немного лучше. Если решения действительно нет, то документирование причин (я полагаю, есть проблемы с XSS?) будет следующим лучшим решением.

Kaia 28.06.2024 22:13

Если все ссылки на эту функцию находятся в атрибутах HTML onclick, просто определите новую функцию и вместо этого сделайте ссылку на нее в этих атрибутах. Будет ли этого достаточно?

trincot 28.06.2024 22:33

Ну, «решения, включающие расширения браузера/привилегированное выполнение» — это совершенно другой пример, чем «букмарклет». Посмотрите chrome.debugger/протокол удаленной отладки.

Ry- 28.06.2024 22:52

Этот вопрос касается именно встроенных скриптов?

Bergi 29.06.2024 01:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Невозможно присвоить новое значение internal_variable, поскольку оно не входит в область действия вашего кода. Вы также не можете назначить новую функцию buttonClicked, поскольку она является константой.

Но в зависимости от реальной ситуации вы можете использовать другие подходы. Вот некоторые из них, которые подойдут для вашего примера:

1. Переопределить innerText

Попросите его изменить число, отображаемое на кнопке, всегда вычитая 100 из значения, которое должно отображаться.

Ваш код будет иметь это:

    Object.defineProperty(document.getElementById("myButton"), "innerText", {
        set(text) {
            // Subtract 100 from the number in the text "Clicked <number> times!"
            text = text.replace(/(Clicked )(\d+)( times!)/, (_, a, b, c) => a + (b - 100) + c);
            // Call the prototype setter for innerText
            Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerText").set.call(this, text);
        }
    });

Сведено в букмарклет:

javascript: {Object.defineProperty(document.getElementById("myButton"),"innerText",{set(text) {text=text.replace(/(Clicked )(\d+)( times!)/,(_,a,b,c)=>a+(b-100)+c);Object.getOwnPropertyDescriptor(HTMLElement.prototype,"innerText").set.call(this, text);}});}

2. Правильный вывод кнопки после ее изменения

Это похоже на предыдущее решение, но изменение текста производится после того, как он уже записан на кнопку innerText. Добавьте обработчик кликов (который будет выполняться после уже подключенного), который выполняет это исправление:

document.getElementById("myButton").addEventListener("click", function () {
    this.innerText = this.innerText.replace(/(Clicked )(\d+)( times!)/, (_, a, b, c) => a + (b - 100) + c);
});

Сведено в букмарклет:

javascript: document.getElementById("myButton").addEventListener("click",function(){this.innerText=this.innerText.replace(/(Clicked )(\d+)( times!)/,(_,a,b,c)=>a+(b-100)+c);})

3. Создайте новую функцию buttonClicked2

Там должен быть код с модификацией счетчика. Затем измените каждый вызов с buttonClicked на buttenClicked2. Здесь я предполагаю, что это похоже на пример, где такая ссылка присутствует только в атрибуте onclick кнопки. Чем больше мест выполняется этот вызов, тем больше функций вам может потребоваться скопировать как новые функции, перемонтировав также ссылки на эту функцию и т. д. Но здесь затрагивается только атрибут onclick:

    var buttonClicked2 = (() => {
        let internal_variable = -100; // Our update
        const _internal_buttonClicked = () => {
            internal_variable++;
            document.getElementById("myButton").innerText = `Clicked ${internal_variable} times!`;
        };
        return _internal_buttonClicked.bind(this);
    })();
    // Redirect the click
    document.getElementById("myButton").setAttribute("onclick", "buttonClicked2()");

Сведено в букмарклет:

javascript: {var buttonClicked2=(()=>{let internal_variable=-100;const _internal_buttonClicked=()=>{internal_variable++;document.getElementById("myButton").innerText=`Clicked ${internal_variable} times!`;};return _internal_buttonClicked.bind(this);})();document.getElementById("myButton").setAttribute("onclick", "buttonClicked2()");}

4. Создайте наполнение страницы <iframe>

В него <iframe> поместите текущий HTML, но с модификацией кода, который вы хотите иметь. Итак страница перезагрузится, но с вашей модификацией и в <iframe>.

if (window === top) {
    // Patch the HTML
    let html = document.documentElement.innerHTML
                .replace("internal_variable = 0;", "internal_variable = -100;");
    let iframe = `<body style = "margin:0"><iframe style = "display:block;border:0;height:100%;width:100%"></iframe></body>`;
    // Replace the current document with just an <iframe>
    document.write(iframe);
    // Write the patched HTML to the frame document
    document.querySelector("iframe").srcdoc = html;
}

Сведено в букмарклет:

javascript: if (window===top){let html = document.documentElement.innerHTML.replace("internal_variable = 0;", "internal_variable = -100;");let iframe = `<body style = "margin:0"><iframe style = "display:block;border:0;height:100%;width:100%"></iframe></body>`;document.write(iframe);document.querySelector("iframe").srcdoc=html;}

Ограничения

Каждое из вышеперечисленных решений имеет свои ограничения. Подходит ли один из них в реальных случаях, во многом будет зависеть от функциональности страницы.

Огромное спасибо за указание награды. Я очень надеюсь, что некоторые части этого ответа были для тебя полезны, @Kaia.

trincot 05.07.2024 18:19

Другие вопросы по теме