Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Стрелочная функция в объекте (https://javascript.ru/forum/misc/76579-strelochnaya-funkciya-v-obekte.html)

Tipylja 23.01.2019 20:52

Стрелочная функция в объекте
 
Здравствуйте, есть вот такая функция-модуль:
var paralax = ( () => {
		const
			bg = document.querySelector('.header__bg')
			,user = document.querySelector('.header__me')
			,text = document.querySelector('.header__img-portfolio');
		
		
		return {
			move: function (block, windowScroll, rateVaue) {
				var shift = windowScroll / -rateVaue + '%';
				var style = block.style;
	
				style.top = shift;
			},
			init: function (windowScroll)  {				
				this.move(bg, windowScroll, 45);
				
			}
	}
	
	})();

Она возвращает два метода move и init, в таком виде она работает, но если эти методы описывать через стрелочные функции то я получаю ошибку
this.move is not a function
Я так понимаю теряется контекст в таком случае? Подскажите пожалуйста, как этого избежать?:-?

рони 23.01.2019 21:15

Tipylja,
вариант...
const paralax = (() => {
const   bg = document.querySelector('.header__bg'),
        user = document.querySelector('.header__me'),
        text = document.querySelector('.header__img-portfolio'),
        move = (block, windowScroll, rateVaue) => {
            const shift = windowScroll / -rateVaue + '%';
            const style = block.style;
            style.top = shift;
        },
        init = (windowScroll) => {
            move(bg, windowScroll, 45);
        };

    return {
        move,
        init
    }

})();

MallSerg 23.01.2019 22:17

Цитата:

Сообщение от Tipylja (Сообщение 502537)
this.move is not a function
Я так понимаю теряется контекст в таком случае? Подскажите пожалуйста, как этого избежать?:-?

Просто нужно разобраться как работает this в javaScript.
paralax.init.move - не существует что и приводит к ошибке

this в JS динамически заменяется в момент вызова функции и всегда указывает в контексте какого объекта он исполняется. В отличии от некоторых языков программирования где он является константным указателем на экземпляр класса.
<script>
function GetName() { return this.name; }
 
var vasa = {name: "Вася"};
var lena = {name: "Лена"};
var petia = {name: "Петя"};
 
vasa.gn = GetName;
lena.gn = GetName;
petia.gn = GetName;
 
document.write ( vasa.gn() + "<br>") ;
document.write ( lena.gn() + "<br>") ;
document.write ( petia.gn() + "<br>") ;
</script>

В JS очень важно понимать как создается и работает контекст исполнения функции (текущая область видимости переменных).

Malleys 23.01.2019 23:17

Цитата:

Сообщение от Tipylja
Подскажите пожалуйста, как этого избежать?

Используйте синтаксический сахар для методов объекта...
const paralax = (() => {
	const
	  bg   = document.querySelector('.header__bg')
	, user = document.querySelector('.header__me')
	, text = document.querySelector('.header__img-portfolio')


	return {
		move(block, windowScroll, rateVaue) {
			const shift = windowScroll / -rateVaue + '%';
			const style = block.style;

			style.top = shift;
		},

		init(windowScroll)  {				
			this.move(bg, windowScroll, 45);
		}
	}
})();

Tipylja 24.01.2019 14:13

Спасибо за ответы. Но все работает и так, в приведенном мною примере, если функции описывать классически путем, а вот если использовать стрелочный синтаксис, то нет.
На сколько я понимаю, то в классическом виде this указывает на возвращаемый объект, который по замыканию видит переменные внутри модуля и методы внутри себя this.move и this.init, но если объявлять функции через стрелочный синтаксис, то this указывает на window, а там никаких move и init нет.
И вопрос в том, как быть, если хочется уйти от классического объявления функции и перейти полностью на стрелочные

Tipylja 24.01.2019 14:23

Цитата:

Сообщение от рони (Сообщение 502538)
Tipylja,
вариант...

Так работает, спасибо!

Malleys 25.01.2019 01:49

Цитата:

Сообщение от Tipylja
Но все работает и так, в приведенном мною примере, если функции описывать классически путем, а вот если использовать стрелочный синтаксис, то нет.

«Стрелочный синтаксис» — это та же самая функция, представитель класса Function. При инициализации ей не назначается внутреннее свойство [[Construct]]. Контекст такой функции связан с this того места, где она создавалась. Т. е. () => {} можно представить как (function() {}).bind(this). Да, в вашем примере this указывает на глобальный объект, поскольку в том месте, где создавалась такая функция, this указывал на глобальный объект. Если бы, например, вы создали такую функцию внутри конструктора Foo, то this внутри неё указывал бы на представителя класса Foo (при соответствующей инициализации new Foo)

Цитата:

Сообщение от Tipylja
И вопрос в том, как быть, если хочется уйти от классического объявления функции и перейти полностью на стрелочные

«Стрелочные функции» не могут быть использованы как конструктор, лучше всего подходят для функций без методов, не имеют собственного объекта arguments, поэтому в теле стрелочных функций arguments будет ссылаться на переменную в окружающей области, вызов стрелочных функций с помощью методов call() или apply(), даже если передать аргументы в эти методы, не влияет на значение this, подходят для функционального программирования. Важно понимать, когда вам нужно, чтобы функция содержала собственный контекст this, а когда нет.

В вашем примере нужно, чтобы функция содержала собственный контекст this, в том решении, которое вам привёл рони, вы всё-таки не можете использовать this, вы не можете вызывать методы в контексте, у вас нет внутри метода ссылки на объект. В моём примере выше (пост №4) я вам показал, как можно избежать потери контекста. (+ БОНУСЫ! не нужно печатать имена методов два раза, не нужно печатать «стрелки»)

Цитата:

Сообщение от Tipylja
хочется уйти от классического объявления функции и перейти полностью на стрелочные

Ограничивая себя таким образом, не нужно забывать, что стрелочная функция является только малой частью того, что может полностью инициализированная функция.

Каким бы образом функция синтаксически не записывалась, она принимает аргументы, производит какие-либо действия, и возвращает результат. И всё!

А вы когда либо задумывались о том, что может существовать нечто, напоминающее функцию, оно тоже принимает аргументы, производит действия, останавливается и возвращает результат. Однако может обратно вернуться и продолжить выполнение дальше! Опять возвратить результат. А представьте две такие функции, которые переходят из одной в другую! Вот это бы я назвал «уйти от классического объявления функции»

Трудяга 02.08.2019 16:10

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

<script>
function sum() {
const params = Array.prototype.slice.call(arguments);

if (!params.length) return 0;

return params.reduce((prev, next) => prev + next);
}
console.log(sum(1, 2, 3, 4)); // 10
console.log(sum()); // 0
</script>

Malleys 02.08.2019 19:48

Цитата:

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

В сообщении выше же сказано, что «стрелочные функции»... не имеют собственного объекта arguments.

Короткий вариант...

function sum(...params) {
	if(!params.length) return 0;

	return params.reduce((prev, next) => prev + next);
}

console.log(sum(1, 2, 3, 4));// 10
console.log(sum());// 0


Длинный вариант...
const sum = (...params) => {
	if(!params.length) return 0;

	return params.reduce((prev, next) => prev + next);
}
console.log(sum(1, 2, 3, 4));// 10
console.log(sum());// 0


Более короткий вариант...
const sum = (...params) => params.reduce((prev, next) => prev + next, 0);
console.log(sum(1, 2, 3, 4));// 10
console.log(sum());// 0


Часовой пояс GMT +3, время: 03:00.