>  기사  >  웹 프론트엔드  >  프런트엔드 고급(11): jQuery 객체에 대한 자세한 그림

프런트엔드 고급(11): jQuery 객체에 대한 자세한 그림

PHPz
PHPz원래의
2017-04-04 17:58:311290검색

프런트엔드 고급(11): jQuery 객체에 대한 자세한 그림

첨부된 사진은 본 글과 무관

프런트엔드를 배우는 초창기에는 다들 jQuery 소스 코드. jQuery 소스코드를 통해 몇 가지 응용 기술을 배울 때, "이렇게도 JavaScript를 사용할 수 있다니!

프런트 엔드가 개발되고 다른 여러 프런트 엔드

프레임워크 가 등장하면서 jQuery는 점차 더 이상 필요하지 않게 되었습니다. 따라서 jQuery에 대한 모든 사람들의 열정이 많이 떨어졌습니다. 하지만 jQuery에서 배운 많은 기술은 여전히 ​​실제 개발에 매우 ​​유용합니다. 이에 대한 간단한 이해는 JavaScript를 더 깊이 이해하는 데에도 도움이 됩니다.

이 기사의 주요 목적은 jquery

객체가 캡슐화되는 방법을 공유하는 것입니다. 누구나 jQuery 소스 코드를 더 자세히 배울 수 있는 입문서라고 볼 수 있습니다.

jQuery 객체를 사용할 때는 다음과 같이 작성합니다.

// 声明一个jQuery对象
$('.target')

// 获取元素的css属性
$('.target').css('width')

// 获取元素的位置信息
$('.target').offset()
사용 초기에는 $가 무엇인지 같은 질문이 많을 수 있습니다.

new를 사용하여 객체 등을 직접 선언하는 것은 어떨까요? 나중에 이에 대해 알게 된 후에 이것이 jQuery 객체 생성의 독창성이라는 것을 깨달았습니다.

먼저 코드로 직접 보여주고, 그런 다음 사진을 사용하여 무슨 일이 일어나고 있는지 모두에게 설명하세요.

;
(function(ROOT) {

    // 构造函数
    var jQuery = function(selector) {

        // 在jQuery中直接返回new过的实例,这里的init是jQuery的真正构造函数
        return new jQuery.fn.init(selector)
    }

    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,

        version: '1.0.0',

        init: function(selector) {
            // 在jquery中这里有一个复杂的判断,但是这里我做了简化
            var elem, selector;
             elem = document.querySelector(selector);
            this[0] = elem;

            // 在jquery中返回一个由所有原型属性方法组成的数组,我们这里简化,直接返回this即可
            // return jQuery.makeArray(selector, this);
            return this;
        },

        // 在原型上添加一堆方法
        toArray: function() {},
        get: function() {},
        each: function() {},
        ready: function() {},
        first: function() {},
        slice: function() {}
        // ... ...
    }

    jQuery.fn.init.prototype = jQuery.fn;

    // 实现jQuery的两种扩展方式
    jQuery.extend = jQuery.fn.extend = function(options) {

        // 在jquery源码中会根据参数不同进行很多判断,我们这里就直接走一种方式,所以就不用判断了
        var target = this;
        var copy;

        for(name in options) {
            copy = options[name];
            target[name] = copy;
        }
        return target;
    }

    // jQuery中利用上面实现的扩展机制,添加了许多方法,其中

    // 直接添加在构造函数上,被称为工具方法
    jQuery.extend({
        isFunction: function() {},
        type: function() {},
        parseHTML: function() {},
        parseJSON: function() {},
        ajax: function() {}
        // ...
    })

    // 添加到原型上
    jQuery.fn.extend({
        queue: function() {},
        promise: function() {},
        attr: function() {},
        prop: function() {},
        addClass: function() {},
        removeClass: function() {},
        val: function() {},
        css: function() {}
        // ...
    })

    // $符号的由来,实际上它就是jQuery,一个简化的写法,在这里我们还可以替换成其他可用字符
    ROOT.jQuery = ROOT.$ = jQuery;

})(window);
위 코드에서는 jQuery 객체의 단순화된 버전을 캡슐화했습니다. jQuery의 전체 프레임워크를 모든 사람에게 간략하게 보여줍니다. 전반적인 프레임워크를 이해한다면 누구나 jQuery 소스 코드를 매우 쉽게 읽을 수 있을 것입니다.

우리는 jQuery 자체가 프로토타입 처리를 위해

, jQuery.fn = jQuery.prototype 등과 같은 영리한 구문을 사용한다는 것을 코드에서 볼 수 있습니다. 이 몇 문장은 제가 아래에서 사용하는 형식적인 jQuery 객체의 핵심입니다. 그림은 논리가 무엇인지 보여줍니다. jQuery.fn.init.prototype = jQuery.fn;

프런트엔드 고급(11): jQuery 객체에 대한 자세한 그림

jQuery 객체 코어 다이어그램

객체 캡슐화 분석

위 구현에서 코드는 먼저 jQuery 생성자에서 fn 속성을 선언하고 프로토타입

을 가리킵니다. 그리고 프로토타입에 init 메소드를 추가했습니다. jQuery.prototype

jQuery.fn = jQuery.prototype = {
    init: {}
}
그런 다음 init 프로토타입을 jQuery.prototype으로 지정했습니다.

jQuery.fn.init.prototype = jQuery.fn;
생성자 jQuery에서는 init의 인스턴스 객체가 반환됩니다.

var jQuery = function(selector) {

    // 在jQuery中直接返回new过的实例,这里的init是jQuery的真正构造函数
    return new jQuery.fn.init(selector)
}
가 드디어 입구를 노출시키면

$를 동일시합니다. jQuery

ROOT.jQuery = ROOT.$ = jQuery;
그래서

$('#test')를 직접 사용하여 객체를 생성하면 실제로 init의 인스턴스가 생성됩니다. 여기서 실제 생성자는 프로토타입의 init 메서드입니다.

참고: jQuery의 내부 구현에 대해 잘 모르는 많은 친구들이 jQuery를 사용할 때 동일한 요소에 대해 다른 작업을 수행하는 등 제약 없이 을 사용하는 경우가 많습니다. $()

var width = parseInt($('#test').css('width'));
if(width > 20) {
    $('#test').css('backgroundColor', 'red');
}
위의 일련의 분석을 통해 우리는

을 실행할 때마다 init의 인스턴스 객체가 재생성된다는 것을 알고 있으므로 제한 없이 jQuery를 사용하면 더 편리해 보이지만 매우 잘못된 것입니다. , 메모리를 많이 소모합니다. 올바른 접근 방식은 동일한 객체이므로 $() 변수 를 사용하여 나중에 사용할 수 있도록 저장하는 것입니다.

var $test = $('#test');
var width = parseInt($test.css('width'));
if(width > 20) {
    $test.css('backgroundColor', 'red');
}

확장 메서드 분석

위 코드 구현에서도 간단하게 두 가지 확장 메서드를 구현했습니다.

jQuery.extend = jQuery.fn.extend = function(options) {

    // 在jquery源码中会根据参数不同进行很多判断,我们这里就直接走一种方式,所以就不用判断了
    var target = this;
    var copy;

    for(name in options) {
        copy = options[name];
        target[name] = copy;
    }
    return target;
}
구현을 이해하려면 먼저 이 점을 분명히 알아야 합니다. 확실하지 않은 경우 돌아가서 이 포인팅에 대한 이전 설명을 읽어보세요. 전달된 매개변수 옵션 개체는 <a href="http://www.php.cn/wiki/1051.html" target="_blank">key<p>: value</p></a> 패턴 개체입니다. , <a href="http://www.php.cn/wiki/1051.html" target="_blank">key</a>: value을 통해 옵션을 탐색하고 key를 jQuery의 새 속성으로 사용하고 value를 새 속성에 해당하는 새 메서드로 사용하여 각각 jQuery 메서드와 jQuery.fn에 추가합니다. for in즉,

을 통해 jQuery를 확장하면 jQuery 생성자에 해당 메서드가 추가되고, jQuery.extend을 통해 jQuery를 확장하면 해당 메서드가 jQuery 프로토타입에 추가된다. jQuery.fn.extend

위의 예에서도 jQuery 내에서 이 두 가지 확장 메소드를 통해 여러 메소드의 구현이 완성된다는 것을 간략하게 보여드렸습니다.

当我们通过上面的知识了解了jQuery的大体框架之后,那么我们对于jQuery的学习就可以具体到诸如css/val/attr等方法是如何实现这样的程度,那么源码学习起来就会轻松很多,也会节约更多的时间。也给一些对于源码敬而远之的朋友提供了一个学习的可能。

有一个朋友留言给我,说她被静态方法,工具方法和实例方法这几个概念困扰了很久,到底他们有什么区别?

其实在上一篇文章中,关于封装一个对象,我跟大家分享了一个非常非常干货,但是却只有少数几个读者老爷get到的知识,那就是在封装对象时,属性和方法可以具体放置的三个位置,并且对于这三个位置的不同做了一个详细的解读。

而在实现jQuery扩展方法的想法中,一部分方法需要扩展到jQuery构造函数中,一部分方法需要扩展到原型中,当我们通读jQuery源码,还发现有一些方法放在了模块作用域中,至于为什么会有这样的区别,建议大家回过头去读读前一篇文章。

而放在构造函数中的方法,因为我们在使用时,不需要声明一个实例对象就可以直接使用,因此这样的方法常常被叫做工具方法,或者所谓的静态方法。工具方法在使用时因为不用创建新的实例,因此相对而言效率会高很多,但是并不节省内存。

而工具方法的特性也和工具一词非常贴近,他们与实例的自身属性毫无关联,仅仅只是实现一些通用的功能,我们可以通过$.each$('p').each这2个方法来体会工具方法与实例方法的不同之处。

在实际开发中,我们运用得非常多的一个工具库就是lodash.js,大家如果时间充裕一定要去学习一下他的使用。

$.ajax()
$.isFunction()
$.each()
... ...

而放在原型中的方法,在使用时必须创建了一个新的实例对象才能访问,因此这样的方法叫做实例方法。也正是由于必须创建了一个实例之后才能访问,所以他的使用成本会比工具方法高很多。但是节省了内存。

$('#test').css()
$('#test').attr()
$('p').each()

这样,那位同学的疑问就很简单的被搞定了。我们在学习的时候,一定不要过分去纠结一些概念,而要明白具体怎么回事儿,那么学习这件事情就不会在一些奇奇怪怪的地方卡住了。

所以通过$.extend扩展的方法,其实就是对工具方法的扩展,而通过$.fn.extend扩展的方法,就是对于实例方法的扩展。那么我们在使用的时候就知道如何准确的去使用自己扩展的方法了。

jQuery插件的实现

我在初级阶段的时候,觉得要自己编写一个jQuery插件是一件高大上的事情,可望不可即。但是通过对于上面的理解,我就知道扩展jQuery插件其实是一件我们自己也可以完成的事情。

在前面我跟大家分享了jQuery如何实现,以及他们的方法如何扩展,并且前一篇文章分享了拖拽对象的具体实现。所以建议大家暂时不要阅读下去,自己动手尝试将拖拽扩展成为jQuery的一个实例方法,那么这就是一个jQuery插件了。

具体也没有什么可多说的了,大家看了代码就可以明白一切。

// Drag对象简化代码,完整源码可在上一篇文章中查看
;
(function() {

    // 构造
    function Drag(selector) {}


    // 原型
    Drag.prototype = {
        constructor: Drag,

        init: function() {
            // 初始时需要做些什么事情
            this.setDrag();
        },

        // 稍作改造,仅用于获取当前元素的属性,类似于getName
        getStyle: function(property) {},

        // 用来获取当前元素的位置信息,注意与之前的不同之处
        getPosition: function() {},

        // 用来设置当前元素的位置
        setPostion: function(pos) {},

        // 该方法用来绑定事件
        setDrag: function() {}
    }

    // 一种对外暴露的方式
    window.Drag = Drag;
})();

// 通过扩展方法将拖拽扩展为jQuery的一个实例方法
(function ($) {
  $.fn.extend({
    becomeDrag: function () {
      new Drag(this[0]);
      return this;   // 注意:为了保证jQuery所有的方法都能够链式访问,每一个方法的最后都需要返回this,即返回jQuery实例
    }
  })
})(jQuery);

后续文章内容一个大概预想

去年年末的时候就有了想要将JavaScript基础知识总结一下的这样一个想法,可是JavaScript基础知识确实并非全部是层层递进的关系,有很多碎片化的东西,所以之前一直没有找到一个合适的整理方法。

直到在segmentfault中我在给题主建议如何快速学习一门诸如react/vue这样的流行框架时,找到了一个好一点的思路,于是就有了这样一系列文章,虽然它并不全面,很多知识没有涉及到,但是其实我是围绕最终通过模块化来构建自己代码这样一个思路来总结的,因此这系列文章能够解决大家最核心的问题。

也正因为如此,这系列的文章的终点将会是在ES6环境下掌握react的使用。虽然前面我多多少少都涉及到了模块的一些概念,但是还差一个实践。因此最终我会以ES6的模块跟大家分享如何使用。

那么后续的文章应该会涉及的内容,就大概包括:

  • 事件循环机制

  • Promise

  • ES6的基础语法

  • ES6에서 일반적으로 사용됨디자인 패턴

  • ES6 모듈

  • ES6과 결합 예

  • React 기본 구문

  • React 컴포넌트

  • React 고차 컴포넌트

  • React 예제

  • Redux

이 시리즈의 기사는 다음과 같은 구체적이고 실용적인 가이드로 간주될 수 있습니다. 단순히 치킨 수프를 통해 학습 방법을 알려주는 것이 아닌, 모두의 학습 방향을 실현 가능한 가이드로 제시합니다. 그러니 이 지식을 배우고 싶은 친구들은 나를 따라오세요! ! ! !

위 내용은 프런트엔드 고급(11): jQuery 객체에 대한 자세한 그림의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.