Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 05.06.2018, 19:15
Интересующийся
Отправить личное сообщение для Yesasha Посмотреть профиль Найти все сообщения от Yesasha
 
Регистрация: 07.01.2018
Сообщений: 15

Задача на хитрость. Обёртка метода. Apply. Bind. Function length.
Здравствуйте. Пишу обёртку для стандартных джаваскрипт функций. Возникает много вопросов, некоторые удаётся разрешить самому, но совет профессионалов был бы очень кстати.

Как правильно сделать обёртку для метода?
Например есть метод Array.prototype.slice, который часто используется для преобразования объекта к массиву.
Можно так:
function slice (obj, begin, end) {
  return Array.prototype.slice.apply(obj, Array.prototype.slice.call(arguments, 1));
}

Тут нам нужно избавиться от первого аргумента и для этого нужно преобразовать аргументы к массиву, это медленно.
Можно так:
function slice (obj, begin, end) {
  // Можно взять метод и непосредственно с функции, но для наглядности оставлю полную версию
  return Function.prototype.call.apply(Array.prototype.slice, arguments);
}

Тут возникает вопрос, поддерживает ли метод .apply arraylike объекты? Информация по этому вопросу расплывчата. Если нет, то придётся приводить к массиву, что в конечном итоге сведёт на нет оптимизацию.
Может быть можно в рантайме определять поддержку и выдавать нужный вариант? Но это сложно и увеличит кол-во кода.
Есть ещё вариант с .bind, но с его поддержкой тоже есть некоторые проблемы, плюс этот вариант не сохранит .length:
var slice = Function.prototype.call.bind(Array.prototype.slice);

Усложняем задачу.
Есть такая вещь как https://github.com/es-shims/es-shim-api
  • In every way possible, the package must attempt to make itself robust against the environment being modified after it is required.
  • For example, require('foo'); delete Function.prototype.call; must not alter the behavior of foo.
  • The most useful technique for this is shown in this example: var bind = require('function-bind'); var slice = bind.call(Function.call, Array.prototype.slice); slice([1], 1); — this technique works in ES3 environments, and will ensure that modifying Array.prototype will not interfere with the package.
В общем проблемы такие, нам советуют использовать .bind, но делая функции на экспорт, надо сохранить .length, а с биндом .length теряется. А без .bind, без бубна никак. Хотя с бубном кое что получилось:
var Function_prototype = Function.prototype;
var Function_prototype_call = Function_prototype.call;
var Function_prototype_apply = Function_prototype.apply;
var Function_prototype_bind = Function_prototype.bind;

// Удаляем все методы из прототипа
Function_prototype.call = null;
Function_prototype.apply = null;
Function_prototype.bind = null;

// Что дальше?
// Что то типа такого
var Array_prototype_slice = Array.prototype.slice;
function slice (obj, begin, end) {
  // Восстановим .apply непосредственно на функции
  Function_prototype_call.apply = Function_prototype_apply;
  return Function_prototype_call.apply(Array_prototype_slice, arguments);
  delete Function_prototype_call.apply; // Удалим
}

Есть идеи получше?
Ответить с цитированием
  #2 (permalink)  
Старый 05.06.2018, 19:37
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,672

Сообщение от Yesasha
нам нужно избавиться от первого аргумента
function slice (obj, begin, end) {
    return Array.prototype.slice.call(obj, begin, end);
}

Про остальное не понял.
Ответить с цитированием
  #3 (permalink)  
Старый 05.06.2018, 19:49
Интересующийся
Отправить личное сообщение для Yesasha Посмотреть профиль Найти все сообщения от Yesasha
 
Регистрация: 07.01.2018
Сообщений: 15

Аргументы begin и end опциональны. Явная передача их может привести к непредсказуемому поведению.
Ответить с цитированием
  #4 (permalink)  
Старый 05.06.2018, 20:20
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,672

Сообщение от Yesasha
может привести к непредсказуемому поведению
Допустим.
Сообщение от Yesasha
поддерживает ли метод .apply arraylike объекты?
На MDN написано что да, начиная с ES5.
Ответить с цитированием
  #5 (permalink)  
Старый 05.06.2018, 21:28
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,010

arguments в apply не то что поддерживается, а даже рекомендуется (в V8/Хроме - это один из паттернов, которые оптимизатор хорошо съедает)

А так - я тоже про остальное не совсем понял. Что надо сделать-то?
Ответить с цитированием
  #6 (permalink)  
Старый 05.06.2018, 22:30
Интересующийся
Отправить личное сообщение для Yesasha Посмотреть профиль Найти все сообщения от Yesasha
 
Регистрация: 07.01.2018
Сообщений: 15

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



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
глобальные или локальные обьекты l-liava-l Оффтопик 27 10.02.2013 23:45
Чем "dequeue после queue" отличается от "dequeue внутри queue". lancer jQuery 2 04.09.2012 14:47
Помогите разобраться ŞΘLƉiΞR Общие вопросы Javascript 2 28.08.2012 11:57
Кроссбраузерная обертка AttachEvent Dim@ Ваши сайты и скрипты 13 21.08.2012 21:21
Свойства посредством полиморфных функций tenshi Ваши сайты и скрипты 0 18.03.2010 17:12