2

使用例如 Chrome 开发者工具,我们可以轻松地检查 JavaScript / jQuery 对象。我试图了解以下内容:

$.ajax    // defined as 'function ...'
$.fn.ajax // undefined

$.removeClass    // undefined
$.fn.removeClass // defined

既然$.removeClass没有定义,我们怎么能调用 eg$('body').removeClass('some-class')呢?而且,这会导致错误$('body').fn.removeClass('some-class')吗?

4

4 回答 4

3

您正在询问两种不同类型的对象。

$是相同的,jQuery并且是一个具有属性的函数。 $.ajax是这些属性之一。

创建的实际 jQuery 对象$('body')实际上是一个对象,它是jQuery.fn.initnot of 的一个实例jQuery

所以,这是你看到不同方法的第一个原因,$因为$('body')它们是不同类型的对象,因此可以有不同类型的方法。


为了进一步理解,方法 on $(它是 的同义词jQuery)是直接添加到jQuery函数本身的方法。在 jQuery 代码中,这主要是jQuery.extend()在 jQuery 对象上完成的。 $.ajax就是其中之一。

jQuery 函数创建的 jQuery 对象上的方法是分配给的方法,jQuery.fn.init.prototype由于 jQuery 的一些诡计,它们是分配给jQuery.fn. 事实证明,当任何东西被分配给 时,它jQuery.fn.init.prototype被设置为同一个对象,它会自动转到并且该原型上的任何东西都会自动成为对象的方法,该对象是由 jQuery 函数创建的,例如or 。jQuery.fnjQuery.fnjQuery.fn.init.prototypejQuery.fn.initjQuery('body')$('body')

您可以在 jQuery 代码中看到这一点。如果您查看 jQuery 函数,它看起来像这样(它创建一个对象,jQuery.fn.init因此将具有来自的方法jQuery.fn.init.prototype

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
},

而且,后来.fn是这样的:

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

这就是分配给的任何方法也是如何jQuery.fnjQuery.fn.init.prototypejQuery 对象上成为方法的。

于 2012-10-02T04:10:31.533 回答
2

当您执行类似的操作时var el = $("#content");,您正在处理几种不同类型的对象:

  • 字符串。 "#content". '纳夫说。
  • 功能。 $(这里是 的同义词jQuery)是一个函数。"#content"正如我们在上面建立的那样,您使用 string 调用它。
  • jQuery 对象。jQuery函数创建 jQuery 对象。el是这些对象之一。

jQuery函数及其直接附加属性大多是不适用于任何特定元素的东西;它们是您可能想要自己做的事情。举个例子,jQuery.ajax; 这不适用于元素,所以它被直接放在jQuery函数上。

其他功能只有在您了解要应用操作的元素的上下文时才有意义。比如说,删除一个类。如果我说jQuery.removeClass("selected");,我想从什么中删除课程?你从来没有指定,所以你不能这样做。相反,假设我们el如上所述分配,el.removeClass("selected");确实有一定的意义;它从代表的任何元素中删除一个类el(这里是 ID 为 的元素content)。

每当我们在点之后有这些函数名称之一时,它就是点之前某些东西的属性(直接或间接)。对于不涉及任何元素的函数ajax,它直接放在$/上jQuery。对于类似的方法removeClass,它被放在所有jQuery对象上。

当然,如果你想添加一个新方法,可以在一组元素上使用,例如removeClass,将这个属性添加到每个元素上会相当乏味,更不用说获取对每个 jQuery 对象的引用的问题了,过去、现在和未来!出于这个原因,jQuery.fn是一个充当所有 jQuery 对象原型的对象。这意味着每当您创建一个新的 jQuery 对象时,它的行为都会像它所基于的原型一样,jQuery.fn. 如果向 中添加一个属性jQuery.fn,它将出现在所有 jQuery 对象上。事实上,原型的概念深深嵌入到 JavaScript 中,修改jQuery.fn会影响所有jQuery 对象,无论是新创建的、过去创建的还是将来创建的。

于 2012-10-02T03:54:31.427 回答
0

我对 jQuery 很陌生,但我的理解是 $.fn 是一个包含所有可以在 jQuery 对象上调用的方法的属性。

这就是为什么当您编写插件时,您通过添加自己的函数定义来扩展 $.fn。

于 2012-10-02T03:52:54.210 回答
0

当你在 JavaScript 中声明一个函数时,它就是一个对象:

function foo() {...}
foo.bar = 'baz'; //set the `bar` property on `foo`

...以及作为构造函数:

var f = new foo();
f instanceof foo; //`true`
f.bar; //undefined

当你从一个函数构造一个对象时,实例会从prototype它的构造函数继承属性:

function Bar() {...}
Bar.prototype = {
    baz: function () {
        console.log('baz');
    }
}
var b = new Bar();
b.baz(); //logs 'baz'
Bar.baz(); //error

此外,JavaScript 中的对象通过引用传递*。

var fizz,
    buzz;
fizz = {};
buzz = fizz;
buzz.foo = 'bar';
console.log(fizz.foo); //logs 'bar'

jQuery 工厂函数 ( jQueryor $) 本质上是**以下列方式定义的:

function jQuery(...args...) {
    //the map returned is a jQuery init object
    return new jQuery.init(...args...);
}
//jQuery.init is a function used as a constructor
jQuery.init = function () {...do stuff...};
//jQuery.init.prototype is an object containing the methods that can be called on
//jQuery.init objects
jQuery.init.prototype = {
    addClass: function () {...},
    on: function () {...},
    removeClass: function () {...}
};
//The jQuery.init.prototype object is exposed via jQuery.fn
jQuery.fn = jQuery.init.prototype;
//functions available on the jQuery namespace are added to the jQuery function object.
jQuery.ajax = function () {};
jQuery.extend = function () {};

*有点
** 过于简单化了

于 2012-10-02T04:12:20.303 回答