12.11.2014, 16:26
|
Новичок на форуме
|
|
Регистрация: 12.11.2014
Сообщений: 6
|
|
Как работает Function.prototype.call.call ?
Читаю документацию и не могу вкурить принцип работы. Например (1):
Function.prototype.call.call(function(){ alert('how it works?') })
Если взять просто call применительно к какому либо методу, то вроде бы все понятно:
например (2):
(function(){ alert(this) }).call({})
согласно документации для call ( п. 15.3.4.4):
При вызове методом call объекта func с аргументом thisArg и необязательными аргументами arg1, arg2, и т.д.,выполняются следующие шаги:
...
4.Вернуть результат вызова внутреннего метода [[Call]] для func, передавая thisArg в качестве значения this и argList в качестве списка аргументов.
В (2) объектом func является анонимная ф-ия,
call вызывает [[Call]] у анонимной ф-ии, подменяя this пустым объектом.
в (1) объектом func является другой call,
call вызывает [[Call]] у call, подменяя this анонимной функцией. И вот что тут дальше происходит непонятно.
В п. 13.2.1
сказано:
При вызове внутреннего метода [[Call]] для объекта Function, называемого F, со значением this и списком аргументов выполняются следующие шаги:
...
2. Пусть result будет результатом вычисления FunctionBody, представляющим собой значение внутреннего свойства [[code]] для F. Если у F нет внутреннего свойства [[code]], или если его значение представляет собой пустое тело функции FunctionBody, то result равен (normal, undefined, empty).
...
Для (2) все понятно - тупо отрабатывает тело нашей функции.
Для (1) - ???
Последний раз редактировалось xaser, 12.11.2014 в 17:08.
|
|
12.11.2014, 16:49
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,589
|
|
Всё просто же. func.call() это вызов call в котором this(для call) == func. Вторым call вы подменяете this для первого call на новую функцию.
Всё точно также как и с обычным кодом:
obj = {
mehod: function(){
alert(this.prop)
},
prop: 'foo'
}
obj.mehod()
obj.mehod.call({prop: 'bar'})
только this не объект, а функция.
__________________
29375, 35
Последний раз редактировалось Aetae, 12.11.2014 в 16:53.
|
|
12.11.2014, 16:50
|
Профессор
|
|
Регистрация: 12.04.2010
Сообщений: 557
|
|
Понять (1) несложно, главное разложить его по косточкам.
var func = Function.prototype.call;
var thisObj = function(){ alert('how it works?') };
тогда получается
func.call(thisObj)
что эквивалентно thisObj.func(), где под "func" в нашем случае подразумевается call, который есть у каждой функции
|
|
12.11.2014, 17:54
|
Профессор
|
|
Регистрация: 09.11.2014
Сообщений: 610
|
|
Сообщение от Aetae
|
Всё просто же. func.call() это вызов call в котором this(для call) == func. Вторым call вы подменяете this для первого call на новую функцию.
|
Я прошу прощения, но, все же давайте проясним.
func.call -- это функция, this которой -- это объект func, который является экземпляром Function
func.call.call -- это функция, this которой -- это объект call, который является экземпляром Function.
Обе они -- экземпляр Function, однако, call, которая вызывается в контексте call, ведет себя иначе, чем call, вызванный в контексте другой функции. Очевидно, что объект call, имеет в себе что-то, помимо того, что он наследует от Function
Так вот, интересно как раз то, что такого есть в call, чего нет в обычном объекте функции. То есть, это что-то, это должно быть тем, что вызывает эффект вызова функции, поданной в качестве аргумента func.call.call(function(){})
|
|
12.11.2014, 18:03
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
Последний call меняет this первого, ничего необычного не вижу.
|
|
12.11.2014, 18:07
|
Новичок на форуме
|
|
Регистрация: 12.11.2014
Сообщений: 6
|
|
Все равно не догоняю.
В 15.3.4.4 сказано про "При вызове методом call объекта func"
Тут под вызовом метода имеется ввиду наличие property accessor, ведь так? То бишь func.call || func['call'].
Ок. Имеем Function.prototype.call - объект func + Function.prototype.call.call - собственно сам метод.
Итак, приступим.
1. IsCallable = true, едем дальше
2, 3. формируем список аргументов, у нас он пустой
4. Вызываем [[Call]] у объекта func (первый call в нашем случае), куда передаем this, равный анонимной функции и пустой список аргументов.
Далее по 13.2.1:
5. Формируем новый execution context, где this будет указывать на анонимную ф-ию
6. Вычисляем FunctionBody (для (2) - это код ф-ии, для (1) - видимо, внутренний код call)
Так вот на этом этапе для (2) - все предельно понятно.
Тогда как для (1) - какая-то магия заставила первый call вызвать [[Call]] у this. Т.е это уже не property accessor, когда мы call через точку присоединяем к функции.
Тут call вдруг "посчитал", что нужно переданный this выполнить в качестве функции.
В общем, либо я сильно торможу, либо не вижу, где этот момент в стандарте описан, либо и то и другое)
Последний раз редактировалось xaser, 12.11.2014 в 18:12.
|
|
12.11.2014, 18:10
|
Новичок на форуме
|
|
Регистрация: 12.11.2014
Сообщений: 6
|
|
Сообщение от krutoy
|
call, которая вызывается в контексте call, ведет себя иначе, чем call, вызванный в контексте другой функции.
|
Вот и я о том же.
Последний раз редактировалось xaser, 12.11.2014 в 18:16.
|
|
12.11.2014, 18:12
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
чтобы представить, что внутри call, можно перезаписать его так:
Function.prototype.call = function (thisObj) {
return this.apply(thisObj, Array.from(arguments).slice(1));
};
тоесть call вызывает свой this
func1.call(…) //внутри call this → func1
func1.call.call(func2) //последний call меняет this первого на func2
никакого специального поведения для call.call нет
Последний раз редактировалось Octane, 12.11.2014 в 18:19.
|
|
12.11.2014, 18:43
|
Профессор
|
|
Регистрация: 09.11.2014
Сообщений: 610
|
|
Сообщение от Octane
|
func1.call(…) //внутри call this → func1
func1.call.call(func2) //последний call меняет this первого на func2
|
Нет. По Вашему определению:
func1.call(…) //внутри call this → func1
func1.call.call(func2) //внутри последнего call this --> call
Никакого первого this уже нет, мы находимся в рантайме. this получает свое значение в рантайме.
|
|
12.11.2014, 18:46
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
прочитай внимательно, я не писал про this внутри последнего call
|
|
|
|