Статьи

Не спеша «это» в JavaScript

В этом посте объясняется, как это можно использовать в JavaScript. Это было вызвано твитом Брендана Эйха.

Чтобы понять, что это не так и почему это полезно, мы сначала должны взглянуть на общие методы.

Универсальные методы

Как правило, метод очень тесно связан с его типом: его можно использовать только для объекта, если объект является экземпляром типа метода. Однако некоторые методы настолько полезны, что было бы неплохо, если бы мы могли применять их и к экземплярам других типов. Например:

    // Simplified version of the actual implementation:
    Array.prototype.forEach = function (callback) {
        for(var i=0; i<this.length; i++) {
            if (i in this) {
                callback(this[i], i);
            }
        }
    };

это можно считать неявным параметром forEach (). forEach () работает с любым этим параметром, который может выполнять следующие задачи.

  • свойство length: this.length
  • Доступ к недвижимости: это [я]
  • Проверка на наличие недвижимости: я в этом

Объект arguments (содержащий фактические параметры функции)
не является экземпляром Array и поэтому не может напрямую использовать forEach (). Но он может делать все вышеперечисленные вещи. Чтобы применить к нему forEach (), нам нужно только сделать этот параметр явным (а не неявным). К счастью, у функций есть метод call (), который позволяет нам сделать это:

    function printArgs() {
        Array.prototype.forEach.call(arguments, function (elem, index) {
            console.log(index+". "+elem);
        });
    }

forEach.call () имеет еще один аргумент, чем forEach (): его первый аргумент является значением этого. Взаимодействие:

    > printArgs("a", "b")
    0. a
    1. b

В JavaScript есть несколько общих методов, большинство из которых находятся в
Array.prototype .

Не торопясь это

Не использовать это в методе означает переход от подписи

    obj.method(arg1, arg2)

на подпись

    method(obj, arg1, arg2)

Uncurry позволяет сделать метод красивее, когда он применяется в целом. Пример:

    Array.forEach = Array.prototype.forEach.uncurryThis();
    function printArgs() {
        Array.forEach(arguments, function (elem, index) {
            console.log(index+". "+elem);
        });
    }

Есть
предложение сделать это для всех методов Array в будущей версии ECMAScript. Ниже приведены три способа реализации uncurryThis.

Версия 1: Что на самом деле происходит [Eich, слегка модифицированный]?

    Function.prototype.uncurryThis = function () {
        var f = this;
        return function () {
            var a = arguments;
            return f.apply(a[0], [].slice.call(a, 1));
        };
    };

Версия 2. Неиспользуемая версия функции аналогична вызову метода call () в оригинале. Мы можем заимствовать этот метод через bind ():

    Function.prototype.uncurryThis = function () {
        return this.call.bind(this);
    };

Версия 3: Лучше всего определять стандартные методы, не слишком полагаясь на внешние методы. Кроме того, bind () не существует до ECMAScript 5. Таким образом, мы переписываем версию 2 следующим образом.

    Function.prototype.uncurryThis = function () {
        var f = this;
        return function () {
            return f.call.apply(f, arguments)
        };
    };

Приведенный выше код все еще находится в духе «заимствования метода call ()».

Карри это

Инверсия uncurryThis (), которая называется curryThis (), полезна всякий раз, когда метод хочет передать свое this во вложенную функцию. Вместо того чтобы писать

    var obj = {
        method: function (arg) {
            var self = this; // let nested function access `this`
            someFunction(..., function() {
                self.otherMethod(arg);
            });
        },
        otherMethod: function (arg) { ... }
    }

ты можешь написать

    var obj = {
        method: function (self, arg) { // additional argument `self`
            someFunction(..., function() {
                self.otherMethod(arg);
            });
        }.curryThis(), // introduce an additional argument
        otherMethod: function (arg) { ... }
    }

Мы превратили неявный параметр this в явный параметр self. Другими словами: мы перешли от динамического к лексическому я. JavaScript был бы проще, если бы это всегда был явный параметр.

Реализация curryThis ():

    Function.prototype.curryThis = function () {
        var f = this;
        return function () {
            var a = Array.prototype.slice(arguments);
            a.unshift(this);
            return f.apply(null, a);
        };
    };

 

С http://www.2ality.com/2011/11/uncurring-this.html