23.01.2019, 20:52
|
Аспирант
|
|
Регистрация: 17.04.2017
Сообщений: 72
|
|
Стрелочная функция в объекте
Здравствуйте, есть вот такая функция-модуль:
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
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,105
|
|
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
}
})();
|
|
23.01.2019, 22:17
|
|
Профессор
|
|
Регистрация: 07.03.2011
Сообщений: 1,138
|
|
Сообщение от Tipylja
|
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 очень важно понимать как создается и работает контекст исполнения функции (текущая область видимости переменных).
|
|
23.01.2019, 23:17
|
|
Профессор
|
|
Регистрация: 20.12.2009
Сообщений: 1,714
|
|
Сообщение от 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);
}
}
})();
|
|
24.01.2019, 14:13
|
Аспирант
|
|
Регистрация: 17.04.2017
Сообщений: 72
|
|
Спасибо за ответы. Но все работает и так, в приведенном мною примере, если функции описывать классически путем, а вот если использовать стрелочный синтаксис, то нет.
На сколько я понимаю, то в классическом виде this указывает на возвращаемый объект, который по замыканию видит переменные внутри модуля и методы внутри себя this.move и this.init, но если объявлять функции через стрелочный синтаксис, то this указывает на window, а там никаких move и init нет.
И вопрос в том, как быть, если хочется уйти от классического объявления функции и перейти полностью на стрелочные
|
|
24.01.2019, 14:23
|
Аспирант
|
|
Регистрация: 17.04.2017
Сообщений: 72
|
|
Сообщение от рони
|
Tipylja,
вариант...
|
Так работает, спасибо!
|
|
25.01.2019, 01:49
|
|
Профессор
|
|
Регистрация: 20.12.2009
Сообщений: 1,714
|
|
Сообщение от 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
|
Интересующийся
|
|
Регистрация: 30.07.2019
Сообщений: 19
|
|
переделать в стрелочную функцию
Добрый день, возникла проблемка( нужно переделать функцию в стрелочную, нижнюю часть я сделал а при изменении верхней, консоль ругается что не переданы аргументы.
<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>
|
|
02.08.2019, 19:48
|
|
Профессор
|
|
Регистрация: 20.12.2009
Сообщений: 1,714
|
|
Сообщение от Трудяга
|
нижнюю часть я сделал а при изменении верхней, консоль ругается что не переданы аргументы.
|
В сообщении выше же сказано, что «стрелочные функции»... не имеют собственного объекта 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
Последний раз редактировалось Malleys, 02.08.2019 в 19:51.
|
|
|
|