JavaScript: вместо передачи «this» в качестве аргумента, как я могу создать функцию, которая будет вызываться для него как объект? - PullRequest
2 голосов
/ 20 сентября 2019

Я новичок в JavaScript и до сих пор разбираюсь в некоторых понятиях, поэтому извините, если вопрос тупой или на него уже дан ответ, но я не знал, что искать, так как терминология языка все еще для меня чужда (оба JavaScriptи английский).В настоящее время я пытаюсь освоить ключевое слово "this" и пытаюсь свести к минимуму код JS внутри HTML-файла и максимально перенести его во внешние файлы.Это мой вопрос:Допустим, я хочу изменить значение абзаца с Hello World! до foo bar, нажав на сам абзац, просто используя ключевое слово "this" и немного JavaScript.

Я могу сделать это во внешнем файле, например:

<!--index.html-->

<p onclick="setParagraphText(this, 'foo bar')">Hello World!</p>


----------------------------------------------
//script.js

function setParagraphText(paragraph, value) {
    return paragraph.innerHTML = value;
}

Или внутри строки, внутри тега:

<p onclick="this.innerHTML='foo bar'">Hello World!</p>

Мой вопрос: возможно ли сделать комбинацию этих двух способов, чтобы значение p не передавалось какаргумент, но вместо этого функция вызывается для него как объект (как во втором примере), но при этом сохраняется способ сделать это во внешнем файле (как в первом примере)?

Что-то вроде строкthis.function(value) вместо function(this, value)

<!--index.html-->

<p onclick="this.setParagraphText('foo bar')">Hello World!</p>

----------------------------------------------
//script.js

function setParagraphText(value) {
    //something with innerHTML = value; or whatever will work
}

Заранее спасибо!

Ответы [ 5 ]

2 голосов
/ 20 сентября 2019

Прежде всего, если вы хотите иметь возможность вызывать вашу функцию на this, вы должны знать, что здесь представляет ключевое слово this.Один из простых способов сделать это - это console.log.

enter image description here

Итак, this - это элемент DOM, на котором включен встроенный JavaScript!Подтверждено здесь: это в встроенном обработчике событий .Хорошо, если вы хотите получить больше информации, console.log §.constructor.

enter image description here

Итак, это HTMLParagraphElement.Вот что вы получите, если вызовете это:

document.createElement("p");

Итак, если вы хотите иметь возможность вызывать this.setParagraphText, все сводится к вызову setParagraphText для объекта HTMLParagraphElement.Но для того, чтобы сделать это, HTMLParagraphElement должен реализовать его, и один из способов сделать это, как предложил субарахнид, - добавить функцию к своему прототипу, чтобы она использовалась всеми его экземплярами.Если вы считаете, что это было бы полезно, взгляните на веб-компоненты.

Вот ссылка: Расширение нативных элементов HTML .

По сути, вы делаете это так(и классная вещь здесь - функциональность, которая изменяет свое содержимое при нажатии на нее, будет инкапсулирована в классе):

<!DOCTYPE html>
<html>
<body>

<script>

	// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class CoolParagraph extends HTMLParagraphElement {

  constructor() {
    super(); 
    this.addEventListener('click', e => this.setParagraphText('new value'));
  }

  setParagraphText(v) {
    this.innerHTML = v;
  }
}

customElements.define('cool-paragraph', CoolParagraph, {extends: 'p'});
		
</script>

<!-- This <p> is a cool paragraph. -->
<p is="cool-paragraph">Cool paragraph! Click on me and the content will change!</p>

</body>
</html>

Так что вам даже не нужно больше писать встроенный Javascript!

Но если вы хотите, чтобы все было по-своему и добавить свой встроенный JavaScript, этоотлично.

<!-- Note the this.setParagraphText(), now it works! -->
<p is="cool-paragraph" onclick="this.setParagraphText('foo bar')">Cool paragraph! Click on me and the content will change!</p>

<!DOCTYPE html>
<html>
<body>

<script>

	// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class CoolParagraph extends HTMLParagraphElement {

  constructor() {
    super(); 
    //this.addEventListener('click', e => this.setParagraphText('new value'));
  }

  setParagraphText(v) {
    this.innerHTML = v;
  }
}

customElements.define('cool-paragraph', CoolParagraph, {extends: 'p'});
		
</script>

<!-- This <p> is a cool paragraph. -->
<p is="cool-paragraph" onclick="this.setParagraphText('foo bar')">Cool paragraph! Click on me and the content will change!</p>

</body>
</html>

Я не знаю, отвечает ли это на ваш вопрос, но, надеюсь, это направит вас в правильном направлении.

2 голосов
/ 20 сентября 2019

Вы можете добавить атрибут data- к вашему тегу p, который будет хранить данные, которые вы хотите, чтобы ваш текст изменил на (то есть: "foo bar"), а затем использовать addEventListener длядобавьте прослушиватель события click к тегам абзаца, которые имеют этот конкретный атрибут data-.Делая это, вы передаете логику javascript в файл javascript и тем самым ограничивает JS, записанный в вашем HTML-файле.

См. Пример ниже:

const clickableElements = document.querySelectorAll('[data-click]');
clickableElements.forEach(elem => {
  elem.addEventListener('click', function() {
    const value = this.dataset.click;
    this.innerHTML = value;
  });
});
<p data-click="foo bar">Hello World!</p>
<p data-click="baz">Hello Moon!</p>
0 голосов
/ 20 сентября 2019

Не знаю, если это то, что вам нужно, но this в функции относится к самой функции, но вы можете отправить в области действия с .call(this, arguments), что означает, что ссылка на this в функциина самом деле область действия HTML-элемента.

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

function setParagraphText(newValue) {
  this.innerText = this.dataset.text + " + " +  newValue;
}
<p data-text="foo bar" onclick="setParagraphText.call(this, 'foo yah')">Hello World!</p>

Также читайте: Javascript call () и apply () против bind ()?

0 голосов
/ 20 сентября 2019

В настоящее время я пытаюсь [...] минимизировать JS-код внутри HTML-файла и переместить как можно больше во внешние файлы.

Тогда как насчет нет? JS код внутри вашего HTML?Это позволяет убить двух зайцев одним выстрелом:

document.getElementById("clickme").addEventListener("click", function() {
  this.innerHTML = "foo bar"
})
<p id="clickme">Hello world!</p>

Слушатель, которого вы добавляете с помощью addEventListener, будет вызываться с this, являющимся элементом, к которому был добавлен слушатель.

0 голосов
/ 20 сентября 2019

Чтобы ваш код работал, вам нужно улучшить прототип HTMLElement с помощью метода setParagraphText (который по сути является просто оболочкой для this.innerHTML = value):

HTMLElement.prototype.setParagraphText = function(value) { 
  this.innerHTML = value; 
};

Теперь что-то вроде этого должно работать:

<p onclick="this.setParagraphText('foo bar')">Hello World!</p>

Но я бы настоятельно рекомендовал не модифицировать нативные прототипы (старые браузеры, такие как IE 9, даже не допускают такой вещи).

...