Как jQuery имеет конструктор $object и методы, связанные с $?

Каким образом jQuery может выполнять $("#foo").addClass("bar") и $.ajax()?

Я создаю структуру микро javascript и хочу создать новый экземпляр объекта, например $("#hello"). С этим объектом существуют связанные методы, такие как addClass, css и т.д., Как и с jQuery. Поэтому я мог бы сделать что-то вроде

$("#foo").addClass("remove").css("color", "red");

Мне удалось создать это. Однако, когда я хочу вызвать метод из этого объекта, например $.ajax, функция конструктора перезаписывается, и я могу вызвать $.ajax, но не $( "# foo" ).

В принципе, как jQuery может выполнять оба?

Ответ 1

ОК, функция $ - это не только функция, но и объект, как и все функции. Таким образом, он может иметь методы. Что все это ajax, это метод функции $. Поэтому мы можем начать с этого:

$ = function(obj) {
  // some code 
};
$.ajax = function (arg1, arg2) {
  // some ajax-y code
};

Пока все хорошо. Теперь, что мы добавили в функцию $? Ну, он должен вернуть объект, и этот объект должен иметь некоторые хорошие методы, определенные на нем. Поэтому нам понадобится функция конструктора (чтобы дать нам новые объекты) и прототип (чтобы обеспечить отличные методы для этих объектов).

$ = function(obj) {
  var myConstructor = function (obj) {
    this.wrappedObj = obj;
  };

  myConstructor.prototype = {
    niftyMethod: function () {
      // do something with this.wrappedObj
      return this; // so we can chain method calls
    },
    anotherNiftyMethod: function (options) {
      // do something with this.wrappedObj and options
      return this; 
    }
  };

  return new myConstructor(obj);
};

Итак, у нас это есть. Мы можем это сделать:

var mySnazzObject = $("whatever");
mySnazzObject.niftyMethod().anotherNiftyMethod(true);        

И мы можем это сделать:

$.ajax("overthere.html", data);

Очевидно, jQuery делает чертов много больше, чем это, и он делает это по-настоящему впечатляюще, но что общая идея.

UPDATE: AS @Raynos был достаточно любезен, чтобы наблюдать, не представив конструктивный ответ, мой оригинальный код создаст прототип ad infinitum. Поэтому мы используем анонимную функцию автоматического выполнения, чтобы объявить конструктор и прототип отдельно:

(function () {
  var myConstructor = function (obj) {
    this.wrappedObj = obj;
  };

  myConstructor.prototype = {
    niftyMethod: function () {
      // do something with this.wrappedObj
      return this; // so we can chain method calls
    },
    anotherNiftyMethod: function (options) {
      // do something with this.wrappedObj and options
      return this; 
    }
  };

  var $ = function(obj) {
    return new myConstructor(obj);        
  };

  $.ajax = function (arg1, arg2) {
    // some ajax-y code
  };

  window.$ = $;  
}());

Ответ 2

$ = function(arg) { console.log("$ function called with " + arg); }
$.ajax = function(arg) {console.log("$.ajax called with " + arg);}
$('foo');
$.ajax('bar');

http://jsfiddle.net/ac7nx/

Я не думаю, что здесь есть какая-то магия. $ - это просто имя глобальной функции. Просто имейте в виду, что в javascript функции являются объектами первого класса, которые могут иметь свои собственные свойства, включая подфункции, что и есть $.ajax.

Поскольку вы упомянули конструкторную функцию, я должен отметить, что здесь нет OO-объектов, а просто регулярных функций (нет new), поэтому функции-конструкторы не играют в этом. Если вы используете ключевое слово new, то, вероятно, вы сбиваетесь с толку. Если вы хотите, чтобы $('#foo') возвращал новый объект, то внутри кода функции $ вы должны создать новый объект с помощью new и вернуть его, что и делает jQuery, но сама функция $ не является конструктор и не должен вызываться с помощью new. Или в случае чего-то вроде $('#someID') внутри этой функции jQuery получает объект-объект из DOM и затем возвращает этот объект, но все же $ - это просто регулярная функция, возвращаемое значение которой является объектом, а не функцией-конструктором.

Ответ 3

Две разные вещи:

$.ajax является прототипированной функцией jQuery, называемой ajax.

Хотя $ ('foo') является вызовом функции jQuery и в зависимости от типа foo он реагирует по-разному. В http://api.jquery.com/jQuery вы можете увидеть, что jQuery (почти то же самое, что и $) может реагировать на три разных типа: селектора, html или обратные вызовы.

Ответ 4

Вы можете имитировать поведение магического jQuery следующим образом:

//define
var _$ = {};
var $ = function(selector) {
           _$.html = function(args) {
                    alert("Doing the method 'html' with arguments " + args 
                           + " for selector " + selector);
                    return _$; //needed for pipeline
        };
        return _$; 
};

$.ajax = function(args){alert("Doing the method 'ajax' "); }

//and try
$("selector1").html("args1").html("args2");
$.ajax("args2");