2016-05-21 2 views
4

Я читаю MDN Article по адресу slice в JavaScript. Я понимаю все, кроме 2-го примера в разделе под названием Array-Like Objects.JavaScript-вызов() и прототип - функция среза

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

var unboundSlice = Array.prototype.slice; 
var slice = Function.prototype.call.bind(unboundSlice); 

function list() { 
    return slice(arguments); 
} 

var list1 = list(1, 2, 3); // [1, 2, 3] 

То, что я не понимаю, как call может прийти сразу после prototype на второй линии.

Обычно я вижу это в виде Array.prototype.slice.call(arguments) или что-то в этом роде.

Я не понимаю поток первых двух строк и как они генерируют эту функцию slice.

+0

за то, что он стоит, вы также можете сделать 'var slice = Array.prototype.slice.call.bind (Array.prototype.slice);' хотя точка вашего примера заключается в том, что 'call' необязательно имеет сначала принадлежать функции «slice», и она не привязана к * любой * функции, пока вы не «привяжете» ее. –

+1

Точно так же, как метод 'toString' объекта происходит из' Object.prototype.toString', метод 'call' работает от' Function.prototype.call'. –

ответ

3

ТЛ; др:

var slice = Function.prototype.call.bind(unboundSlice); 

короткий способ написания:

var slice = function(value, start, end) { 
    return unboundSlice.call(value, start, end); 
}; 

Давайте подумаем об этой линии на второй:

Array.prototype.slice.call(arguments) 

.slice является метод массива для извлечения подмножества массива. Он работает от значения this. .call - это метод, который имеет каждая функция, он позволяет установить значение this для выполнения функции. Таким образом, приведенная выше строка позволяет нам выполнить slice в качестве метода от arguments без необходимости мутировать arguments. Мы могли бы сделать

arguments.slice = Array.prototype.slice; 
arguments.slice(); 

но это не так чист.

Теперь, глядя на

Function.prototype.call.bind(unboundSlice); 

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

function call(thisValue, arg1, arg2, ...) { 
    return this.apply(thisValue, [arg1, arg2, ...]); 
} 

Обратите внимание, как она называет this как функция.

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

Давайте рассмотрим, что результирующая функция call.bind(unboundSlice) будет выглядеть:.

function boundCall(thisValue, arg1, arg2, ...) { 
    return unboundSlice.apply(thisValue, [arg1, arg2, ...]); 
} 

Мы просто заменили this с unboundSlice. boundCall теперь будет всегда звонить unboundSlice.

+0

Благодарим вас за подробное объяснение. Я буду читать это много раз. Я чувствую, что он начинает нажимать, это всего лишь вопрос времени. – qarthandso

4

MDN article для Function.prototype.call() помог мне обернуть мою голову вокруг этого.

Наиболее упрощенным способом я могу ответить:

В JavaScript функция имеет метод, называемый call. Функция представляет собой объект , и все объекты наследуют методы и свойства от их прототипа .

Итак, ваш пример Array.prototype.slice.call(arguments) показывает вызов метода вызова для функции среза.

Вторая строка в коде, которую вы путаете: var slice = Function.prototype.call.bind(unboundSlice); показывает метод вызова, принадлежащий прототипу функции.

Оформить заказ JavaScript Prototypes, если вы все еще смущены.

1 Функции - это объекты.

2 «Каждый объект JavaScript имеет прототип».

3 «Прототип также является объектом».

4 «Все объекты JavaScript наследуют их свойства и методы от их прототипа».

Другими словами, вернемся к самому упрощенному способу ответить на это: в javascript функция имеет метод, называемый call.

Что касается понимания того, что делает bind, пример that = this против .bind в this статье помогает понять, что происходит.

Если это сбивает с толком, то убедитесь, что вы понимаете context and scope

2

slice является собственностью Array.prototype, и он ожидает, что его this объекта будет массивом типа.Вы можете использовать его на массив как объекты (которые имеют свойство длины и обладают свойствами, которые можно индексировать), которые не имеют свои собственные функции среза так:

Array.prototype.slice.call(arraylikething); 

Это много печатать, так что мы может сделать функцию, чтобы сделать то же самое:

var slice = function(arraylikething){ 
    return Array.prototype.slice.call(arraylikething); 
}; 

JavaScript обеспечивает Function.prototype.bind для связывания функций указанного this объекта. Таким образом, мы можем сделать то же самое немного легче:

var slice = Function.prototype.call.bind(Array.prototype.slice); 

bind создает новую функцию, которая возвращает результат call с this объекта, установленным в Array.prototype.slice, то же самое, что мы делали вручную выше, и эквивалентно ваш код.

0

В первой строке Array.prototype.slice (который является методом) просто ссылается на unboundSlice. Вы по существу «извлекаете» метод среза от Array.prototype.

Во второй строке то же самое происходит для Function.prototype.call, что также является методом ВСЕХ функций. (он определен в Function.prototype и унаследован всеми функциями).

Далее, с помощью .bind(unboundSlice)this значение вызов функции является связан с ссылкой на Array.prototype.slice, который по существу приводит к одной и той же вещи, как Array.prototype.slice.call(), где вызов также имеет свою this обязан slice, из-за того, что это способ его , И потому, что это называется так.

Наконец, метод связанного вызова ссылается через var slice;

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

Так что теперь, вместо вызова call, когда он уже был метод slice, вы связываете slice быть значение callthis для того, чтобы достичь такого же поведения.

1

Ответ от Криса Диллинджера правильный и информативный. Но вот еще один способ подумать об этом. Вы просили, по существу, определить

Function.prototype.call.bind(Array.prototype.slice) 

Что вы можете посмотреть на этом пути:

fn.bind(context) 
    ==> function(...args) {return context.fn(...args);} 
      // 1. definition of `bind` (oversimplified, but enough for this case) 

fn.bind(unboundSlice) 
    ==> function(...args) {return unboundSlice.fn(...args);} 
      // 2. substitute `unboundSlice` for `context` 

Function.prototype.call.bind(unboundSlice) 
    ==> function(...args) {return unboundSlice[Function.prototype.call](...args);} 
      // 3. substitute `Function.prototype.call` for `fn`. 

Function.prototype.call.bind(unboundSlice) 
    ==> function(...args) {return unboundSlice[.call(...args);} 
      // 4. walk the prototype chain 

Function.prototype.call.bind(Array.prototype.slice) 
    ==> function(...args) {return Array.prototype.slice.call(...args);} 
      // 5. substitue `Array.prototype.slice` for `unboundSlice` 

Единственный шаг, который даже немного сложнее это шаг 4, где вы должны понимать, что все функции наследуют метод call из их цепочки прототипов, поэтому обращение к ним call - это просто альтернативный способ вызова самих функций.

+0

Выполнение этого шаг за шагом действительно помогло мне понять это. Большое спасибо. – qarthandso

Смежные вопросы