Этот синтаксис JavaScript я не видел до сих пор, что он делает на самом деле? - PullRequest
22 голосов
/ 14 июля 2010

Сегодня я увидел синтаксис JavaScript (при вызове функции), который мне незнаком.Это было похоже на

def('Person') ({
  init: function(name) {this.name=name;}
  ,speak: function(text) {alert(text || 'Hi, my name is ' + this.name);}
});

и

def('Ninja') << Person ({
  kick: function() {this.speak('I kick u!');}
});

1: что происходит с объектом в скобках в первом примере?Он как-то обрабатывается функцией def, но я не понимаю, что здесь происходит (см. Функцию def ниже).Куда уходит объект?

2: Примерно то же самое, но с использованием оператора <<, которого я никогда не видел (я думаю!).О чем это все?

Код взят из http://gist.github.com/474994,, где Джо Далтон сделал небольшую вещь JavaScript-OO-наследования (это, очевидно, форк чужой работы, но довольно тщательно переписанныйкак это выглядит).Может быть, вы хотите проверить это на предмет того, на что ссылается функция def, которую я вам дам здесь:

function def(klassName, context) {
  context || (context = global);

  // Create class on given context (defaults to global object)
  var Klass =
    context[klassName] = function Klass() {

      // Called as a constructor
      if (this != context) {

        // Allow the init method to return a different class/object
        return this.init && this.init.apply(this, arguments);
      }

      // Called as a method
      // defer setup of superclass and plugins
      deferred._super = Klass;
      deferred._plugins = arguments[0] || { };
    };

  // Add static helper method
  Klass.addPlugins = addPlugins;

  // Called as function when not
  // inheriting from a superclass
  deferred = function(plugins) {
    return Klass.addPlugins(plugins);
  };

  // valueOf is called to set up
  // inheritance from a superclass
  deferred.valueOf = function() {
    var Superclass = deferred._super;
    if (!Superclass)
        return Klass;
    Subclass.prototype = Superclass.prototype;
    Klass.prototype = new Subclass;
    Klass.superclass = Superclass;
    Klass.prototype.constructor = Klass;
    return Klass.addPlugins(deferred._plugins);
  };
  return deferred;
}

Ответы [ 2 ]

13 голосов
/ 14 июля 2010

1: вызов def('Person') возвращает функцию, которая вызывается с объектом в качестве параметра.Это тот же принцип, что и:

function x() {
  return function(y) { alert(y); }
}

x()('Hello world!');

2: оператор << является оператором левого сдвига.Он сдвигает целочисленное значение на определенное количество бит влево.Я не нашел никаких ссылок для какого-либо другого использования для него, и в Javascript нет перегрузки операторов, поэтому я не могу иметь никакого смысла использовать его в функции.Пока это выглядит как опечатка для меня.

Редактировать:

Как объяснил Тим, оператор сдвига просто используется для вызова метода valueOf.Он работает как перегрузка всех операторов, принимая первоначальное назначение и делая что-то совершенно другое.

5 голосов
/ 15 июля 2010

Вау, это было достаточно запутанно, чтобы мой крошечный мозг мог понять, но теперь я чувствую себя намного лучше, зная, как именно это работает :) Спасибо @Tim за указание на valueOf() трюк.

Общий случай создания "class" с использованием:

def ("ClassName") ({
    init: function() { .. },
    foo: function() { .. }
});

тривиален, так как первый вызов def возвращает функцию, которая принимает объект, и копирует свойства переданного объекта впрототип ClassName.

Более интересный случай использования << для подкласса основан на порядке вычисления выражения, а также на попытке принудительного приведения любого объекта к значению неявным вызовом valueOf().Основной трюк - это, по сути, общая переменная, которая записывает суперкласс и свойства, которые к нему применяются.Выражение

def("ClassName") << ParentClass({ .. })

будет оцениваться следующим образом:

  1. def("ClassName") вызывается, создает глобальный объект ClassName и возвращает его функцию конструктора.Давайте назовем этот возвращенный объект - initializeMeLater.
  2. ParentClass(..), который хранит ссылку на ParentClass и переданный объект / свойства в общей переменной.
  3. initializeMeLater.valueOf() вызывается, который получает ссылку на родительский класс и свойства из этой общей переменной и устанавливает прототипы.
  4. valueOf вызывается для возвращаемого значения из шага 2, который бесполезен и имеетбезрезультатно, так как мы уже настроили отношение суперкласса на шаге 3.

Код пытается эмулировать синтаксис Ruby для создания подклассов, который выглядит следующим образом:

class Child < Parent
    def someMethod
        ...
    end
end
...