С Новым годом! Форум программистов, компьютерный форум, киберфорум
JavaScript для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4

(new Function).call.call.call.call.call.call(­myFunc);

07.11.2020, 15:30. Показов 2272. Ответов 22
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
JavaScript
1
2
3
4
5
6
7
8
myFunc = function(x) { console.log('Привет!'); };
 
myObj = {};
 
(new Function).call.call.call.call.call.call(myFunc); // напишет "Привет!"
 
(new Function).call.call.call.call.call.call(myObj); // ошибка
 // Uncaught TypeError: (intermediate value).call.call.call.call.call.call is not a function
Мой главный вопрос: почему call срабатывает с первым аргументом в виде функции, хотя по правилам там должен быть контекст, т.е. объект. Но если я даю объект, то ошибка.

Итак, что для меня понятно:
1) call можно применять к любой функции. метод - это тоже функция, а call - это метод.
2) .call.call.call.call.call.call - количество этих call неважно, там уже зацикленность идёт, потому что свойство call функции call ссылается на саму себя.
3) *****.call.call.call.call(myFunc) - уже не важно, что слева идёт, потому что последний call - это запуск с заданным this предпоследнего call, а он - это "native code", т.е. Function.prototype.call
Поэтому:
(new Function).call.call.call.call.call.call(myFunc);
то же самое, что
Function.prototype.call.call(myFunc);

Т.е. я как бы хочу вызвать Function.prototype.call в моём контексте this. Я ставлю по правилам контекст this в виде ссылки на объект, но даёт ошибку. А вот если ставлю туда функцию, то ошибки нет. Мало того, эта функция, переданная в качестве контекста, запускается.

Почему не работает передача this-контекста?
Почему нормально работает со ссылкой на функцию и почему она запускается?
2
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.11.2020, 15:30
Ответы с готовыми решениями:

Выдает ошибку Uncaught RangeError: Maximum call stack size exceeded
Добрый час ! Подскажите, почему происходит переполнение стэка? Как написать, чтобы задуманное выполнялось ? var me = { firstName...

cannot call methods on dialog prior to initialization; attempted to call method 'close'
Добрый день! Я пытаюсь перенести вот этот пример в ASP MVC4 проект: http://jsfiddle.net/rniemeyer/WpnTU/ Поставил те же библиотеки...

Семантика javascript (function() {.}).call(this);
Если кому не сложно объясните данную семантику javascript своими словами. Заранее спасибо (function() {...}).call(this);

22
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
07.11.2020, 18:29
Ну шо можно сказать? Тёмная сторона вселенной JavaScript...
Какой-то странный случай - при отсутствии тела функции запускать thisArg как функцию.
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
07.11.2020, 22:15  [ТС]
Лучший ответ Сообщение было отмечено amr-now как решение

Решение

amr-now, тело функции есть - это call, код который мы не видим. Её и запускаем c помощью её самой и передаём как бы свой this, но эффект странный.

Добавлено через 48 минут
Вот тут товарищ объясняет:
https://stackoverflow.com/ques... otype-call
JavaScript
1
2
3
fn.call(thisvalue); // (1) is equivalent to
(fn.call).call(fn, thisvalue); // (2) or:
(Function.protoype.call).call(fn, thisvalue); // (3)
Я вроде как понял...
Код (fn.call) в строке 2 из-за скобок возвращает функцию call, теряя контекст fn. Поэтому этот fn надо вернуть первым аргументом при вызове call на call, а вторым аргументом уже идёт аргумент для "первой" call.

Я только не пойму, почему fn запускается. Это же только контекст, т.е. объект. Да, функция - это объект, но почему там возникает вызов?

Добавлено через 17 минут
Вот нашел ещё:
https://stackoverflow.com/ques... -really-do

In fact, Function.prototype.call.call(b) is an Exotic Object, furthermore, a Bound Function Exotic Object.

[Specification] A bound function is an exotic object that wraps another function object.

[Specification] Calling a bound function generally results in a call of its wrapped function.

So that Function.prototype.call.call(a) simply means a().
Короче, примем это просто за такой любопытный факт недр JS.
2
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
07.11.2020, 23:13
DimaDima1985, честно говоря вообще ничего странного не вижу. call является методом типа Function и по умолчанию для него контекстом является как раз таки та самая функция, методом которой он и является. Что делает метод call? Правильно, он вызывает функцию контекста. Если в качестве контекста ему передается другая функция, что по-твоему он должен с ней сделать?
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
07.11.2020, 23:38
diadiavova, call вызывает не функцию контекста, а тупо функцию левее точки. В аргументах подкидывает thisArg и ...params аргументов, которые должны были передаваться не в извращенном использовании функции левее точки.

В сущности мы с DimaDima1985 в шоке от неожиданного поведения объекта-функции call. Неочевидное поведение.
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
07.11.2020, 23:50  [ТС]
Цитата Сообщение от diadiavova Посмотреть сообщение
Правильно, он вызывает функцию контекста.
Нет. amr-now всё правильно написал. Он вызывает ту функцию, на которой вызван call через точку и лишь меняет контекст вызова, т.е. значение this.
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 00:47
Цитата Сообщение от amr-now Посмотреть сообщение
call вызывает не функцию контекста, а тупо функцию левее точки.
А это разные вещи? Ну давай проверим.
JavaScript
1
2
3
4
5
6
7
8
        let obyektLevee = {
            "msg": "Я объект, что левее."
        };
        obyektLevee.getContextMessage = function ()
        {
            return this.msg;
        }
        console.log(obyektLevee.getContextMessage());
Что по-твоему появится в консоли?
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 09:07  [ТС]
Цитата Сообщение от diadiavova Посмотреть сообщение
Ну давай проверим.
В этом примере нет call
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 09:42
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
В этом примере нет call
То есть она в данной ситуации работает как-то иначе?
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 09:59  [ТС]
Цитата Сообщение от diadiavova Посмотреть сообщение
То есть она в данной ситуации работает как-то иначе?
В какой ситуации?
Вы, похоже не поняли вообще о чем речь.
Смысл в том, что call, вызванная в качестве метода самой себя, воспринимает первый переданный параметр как функцию и запускает (!) её, хотя должна первым параметром принимать объект, как значение this.

По правилам синтаксиса call запускают ту функцию, на которой она вызвана как метод.
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 10:25
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
Вы, похоже не поняли вообще о чем речь.
Вообще-то понял. Даже объяснил почему так происходит. amr-now на это возразил, что, дескать "то, что левее - вовсе не то же самое, что и this" и мой пример показал, что через this как раз-таки осуществляется доступ к "тому, что левее".
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
воспринимает первый переданный параметр как функцию
А как что она должна ее воспринимать? Еще раз: call является методом именно функции и для нее this - это функция. Теперь смотрим что происходит. У нас есть последовательность из нескольких call, не важно сколько их, поскольку отработают только последние две. Теперь эти последние две назовем левой и правой функциями соответственно. Сначала вызывается правая с переданной ей функцией в качестве аргумента. Что она делает? Она вызывает левую функцию, попутно передавая ей новый контекст. Таким образом в конечном итоге будет вызвана левая функция call(она же предпоследняя в цепочке, поскольку дальше дело не пойдет) и для нее this будет возвращать наш переданную в качестве аргумента функцию. Что она сделает со своим новым зысом? Да ровно то же самое, что сделала бы и со старым, то есть вызовет его, но уже без аргументов. То есть для исходной функции call, this возвращал "объект слева", а в нашем случае он будет заменен собственной функцией. Вот собственно вот это самое и происходит. Можно еще с контекстом самой передаваемой функции поиграться, его можно передать как второй аргумент.

Добавлено через 12 минут
Цитата Сообщение от diadiavova Посмотреть сообщение
Можно еще с контекстом самой передаваемой функции поиграться, его можно передать как второй аргумент.
Маленькая иллюстрация.
JavaScript
1
2
3
4
5
6
7
8
9
10
        var msg = "Сообщение из окошка";
        let obj = {
            "msg": "Сообщение из объекта"
        };
        obj.printMsg = function ()
        {
            console.log(this.msg);
        };
        Function.prototype.call.call(obj.printMsg);
        Function.prototype.call.call(obj.printMsg, obj);
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 10:28  [ТС]
Вы все верно пишете, но вот начиная отсюда:
Цитата Сообщение от diadiavova Посмотреть сообщение
Что она сделает со своим новым зысом? Да ровно то же самое, что сделала бы и со старым, то есть вызовет его, но уже без аргументов.
Почему? Почему вызовет? Ваше объяснение таково, будто call вызывает первый параметр. Но как можно вызвать обычный объект, а не функцию? Ведь в синтаксисе call func.call([thisArg[, arg1, arg2, ...argN]])
thisArg - это обычный объект, его вызов даст исключение TypeError: myObj is not a function.

Добавлено через 3 минуты
Цитата Сообщение от diadiavova Посмотреть сообщение
Function.prototype.call.call(obj.printMs g);
А теперь напишите так:
JavaScript
1
Function.prototype.call.call(obj);
По правилам синтаксиса я имею право передать объект. Но будет исключение в консоли.
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 10:33
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
будто call вызывает первый параметр.
Не первый параметр, а this. Тут нюанс в том, что первым аргументом наша функция будет именно для правой функции, а для левой она будет зысом.
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
Но как можно вызвать обычный объект, а не функцию?
Да никак его нельзя вызвать, именно поэтому попытка передать обычный объект вместо функции результата не дает. Но при этом не следует забывать и о том, что функция - это тоже объект. То есть не каждый объект можно использовать как функцию, но с функцией можно делать то же, что и с другими объектами, в частности передавать их по ссылке. Именно это и происходит с методами функций, эти методы получают именно функцию в качестве this, а стало быть и при подмене зыса им тоже надо передавать функцию.
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
Ведь в синтаксисе call func.call([thisArg[, arg1, arg2, ...argN]])
thisArg - это обычный объект, его вызов даст исключение TypeError: myObj is not a function.
Обычный-то он обычный, но он не абы какой, он должен удовлетворять каким-то критериям, которые на него накладывают условия использования. В данном случае, когда он заменяет зыс в методе функции, он должен быть функцией, потому что его будут вызывать.
1
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 10:40  [ТС]
Всё, я разобрался!
diadiavova, спасибо вам, хотя вы не объяснили, но натолкнули на размышление. Сейчас для amr-now напишу.
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 10:44
DimaDima1985, еще маленькая иллюстрация
JavaScript
1
2
3
4
5
6
7
8
9
10
        Function.prototype.thisTest = function ()
        {
            console.log(typeof this);
        }
 
        function myFunc()
        {
 
        }
        myFunc.thisTest();
Это к вопросу о том, что возвращает this для метода функции.

Добавлено через 47 секунд
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
хотя вы не объяснили,
Вообще-то объяснил )))
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 10:54  [ТС]
Тут дело в том, КАК работает call, ЧТО именно он делает, хоть мы и не видим его внутренний код.

Вот обычный вызов call:

1) myFunc.call(obj, arg);

Здесь привычный синтаксис, всё понятно. Но что именно call делает? Он как бы переносит myFunc внутрь obj и как бы делает его свойством myFunc. Поэтому получается так после использования call:

2) obj.myFunc(arg);

Вот и всё. myFunc вызывается из obj - значит, в myFunc в качестве this сидит obj.


Идём далее. Помечу два call цифрами, чтобы не путаться:

1) call1.call2(myFunc, arg);

превращается внутри обработчика javascript в:

2) myFunc.call1(arg);

парам-папам. myFunc вызывается! Ну и параметр у неё arg.


В общем, некорректно говорить, что call "подменяет" this где-то в недрах интерпретатора. Метод call именно переносит функцию, на которой вызван, внутрь объекта и оттуда уже вызывает её.

Добавлено через 6 минут
Всё это можно было бы сразу понять, если бы был виден внутренний native код метода call, ну или если бы учебники четко объясняли, ЧТО именно делает call. Нет там никакой хитрой подмены "this", там временный перенос в объект, вызов и удаление из объекта.
1
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 10:59
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
В общем, некорректно говорить, что call "подменяет" this где-то в недрах интерпретатора.
Уж не знаю, что там некорректного. Зыс - это просто служебное слово, обозначающее ссылку на некий объект. Обычно для метода этим объектом является объект, вмещающий данный метод, но с помощью функций call, apply и bind такое положение можно изменить. И хоть я и не говорил, что что-то там чего-то подменяет в каких-то там недрах, тем не менее не вижу в этом определении ничего некорректного.
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
Метод call именно переносит функцию, на которой вызван, внутрь объекта и оттуда уже вызывает её.
А вот это уже точно некорректно. Не переносит, а this именно ссылается на функцию, поскольку функция является объектом и на нее можно ссылаться.
0
331 / 238 / 80
Регистрация: 15.11.2017
Сообщений: 453
Записей в блоге: 4
08.11.2020, 11:16  [ТС]
diadiavova, ваше объяснение я тоже стал понимать, но по моему объяснению можно даже написать
альтернативную функцию и запихнуть её в Function.prototype и будет некий аналог call.

Добавлено через 3 минуты
Или вот так можно объяснить:
в строке myFunc.call(obj, arg);
для метода call в качестве this является функция myFunc (ведь функция - это тоже объект) и call её вызывает, передавая в неё arg.
0
 Аватар для diadiavova
7258 / 2605 / 744
Регистрация: 11.04.2015
Сообщений: 4,148
Записей в блоге: 43
08.11.2020, 11:23
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
о по моему объяснению можно даже написать
альтернативную функцию и запихнуть её в Function.prototype и будет некий аналог call.
Без использования встроенных call, apply и bind? Было бы любопытно на это посмотреть.

Добавлено через 2 минуты
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
Или вот так можно объяснить:
А я как объяснил?
Цитата Сообщение от diadiavova Посмотреть сообщение
честно говоря вообще ничего странного не вижу. call является методом типа Function и по умолчанию для него контекстом является как раз таки та самая функция, методом которой он и является. Что делает метод call? Правильно, он вызывает функцию контекста. Если в качестве контекста ему передается другая функция, что по-твоему он должен с ней сделать?
Это цитата моего самого первого поста.
1
 Аватар для web_coder2
755 / 359 / 100
Регистрация: 04.10.2018
Сообщений: 548
08.11.2020, 12:29
Всем привет особенно DimaDima1985, мы с тобой уже не первый раз пытаемся понять JS XD

Я тут порылся в Интернетах и нашел несколько реализаций call

Вот код

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function.prototype.c = function(newcontext, ...arg){
    let demoFn = (
        thisFunction,
        thisNewContext,
        arg) =>
    {
        thisNewContext["f"] = thisFunction // подмена контекста
        let r = thisNewContext.f(arg)
        console.log(thisNewContext)
        return r
    }
    demoFn(this, newcontext, arg);
}
 
myFunc = function(x) { console.log('Привет!'); };
 
myObj = {};
 
(new Function(`{console.log("Hello")}`)).c.c.c.c.c.c(myFunc); // напишет "Привет!"
Цитата Сообщение от DimaDima1985 Посмотреть сообщение
.call.call.call.call.call.call - количество этих call неважно, там уже зацикленность идёт, потому что свойство call функции call ссылается на саму себя.
И тут ты уже дал по сути ответ, она вызывает сама себя, а что будет если она будет вызывать саму себя у нее просто закончатся контексты xD

И в приведенном примере мы не увидим Hello

JavaScript
1
(new Function).call.call.call.call.call.call(myObj); // ошибка
А в этом примере мы захотим запустить объект

Добавлено через 1 минуту
А еще я узнал про новый синтаксис new Function
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.11.2020, 12:29
Помогаю со студенческими работами здесь

Call a member function query() on a non-object
Сижу уже битый час и не могу понять в чем загвоздка. Я только начинаю изучать js и те решения проблемы которые предлагают просторы...

Call a member function query() on a non-object
Сижу уже битый час и не могу понять в чем загвоздка. Я только начинаю изучать js и те решения проблемы которые предлагают просторы...

prototype.slice.call()
Наткнулся на такую конструкцию: "чтобы вызвать другую функцию с теми же аргументами, но кроме первого, можно создать из arguments...

Отличия call (apply) от bind
Доброго времени суток! Есть такой вопрос! Не могли бы мне обьяснить, когда именно используется call (apply) и когда bind? И, если есть...

API Call HTTP Request
Всем добрый день, Есть у меня следующий API Reuqest, хочу понять по частям каждая часть что из себя представляет, ну например...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru