JQuery源码解析-JQuery的工具方法(3)

 这篇文章主要对下面这几个方法进行解释

  error();抛出异常

  parseHTML():解析节点

  parseJSON():解析JSON

  parseXML:解析XML

  noop():空函数

  globalEval():全局解析JS

  camelCase():转驼峰

  nodeName():是否为指定节点(内部)

error:方法:

error方法的作用是抛出一个自定义异常,内部直接调用了原生解释的throw new Error

error: function( msg ) {
        throw new Error( msg );
    },

parseHTML:方法

这个方法是将字符串转成html节点数组,例如:

        var str = "<li>1</li><li>2</li>";
        var arr = $.parseHTML(str, document, false);
        console.log(arr);

看下源码:

// data: string of html
    // context (optional): If specified, the fragment will be created in this context, defaults to document
    // keepScripts (optional): If true, will include scripts passed in the html string
    parseHTML: function( data, context, keepScripts ) {
        if ( !data || typeof data !== "string" ) {
            return null;
        }
        if ( typeof context === "boolean" ) {
            keepScripts = context;
            context = false;
        }
        context = context || document;

        var parsed = rsingleTag.exec( data ),
            scripts = !keepScripts && [];

        // Single tag
        if ( parsed ) {
            return [ context.createElement( parsed[1] ) ];
        }

        parsed = jQuery.buildFragment( [ data ], context, scripts );

        if ( scripts ) {
            jQuery( scripts ).remove();
        }

        return jQuery.merge( [], parsed.childNodes );
    },

首先第一个if是对参数进行判断,第二个if是对参数进行处理,如果第二个参数为bool类型的时候,把执行上下文赋值成document,

var parsed = rsingleTag.exec( data ),

这个句话是匹配单标签的,如果是标签,则直接用document.createElement方法创建就可以了。

接下来对第三个参数进行判断,也就是是否可以加载script标签:

scripts = !keepScripts && [];

如果传入为false的话,则给一个空数组,如果为true,scripts则为false

// Single tag
        if ( parsed ) {
            return [ context.createElement( parsed[1] ) ];
        }

        parsed = jQuery.buildFragment( [ data ], context, scripts );

这段先对单标签进行处理,如果是多标签,则调用buildFragment方法进行处理。这个方法以后会说到。

    if ( scripts ) {
            jQuery( scripts ).remove();
        }

        return jQuery.merge( [], parsed.childNodes );

如果script不为false的话,则将script标签移除,最后通过merge方法,将其转换成数组。

parseJSON:方法,

这个方法是将标准的json字符串转换为json对象,例如:

       var str = '{"Name":"jam"}';
        console.log($.parseJSON(str).Name); //jam 

源码:

parseJSON: JSON.parse,

源码内部直接调用了原生的方法。

parseXML:方法

这个方法是将xml字符串转换为xml节点的,源码如下:

// Cross-browser xml parsing
    parseXML: function( data ) {
        var xml, tmp;
        if ( !data || typeof data !== "string" ) {
            return null;
        }

        // Support: IE9
        try {
            tmp = new DOMParser();
            xml = tmp.parseFromString( data , "text/xml" );
        } catch ( e ) {
            xml = undefined;
        }

        if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
            jQuery.error( "Invalid XML: " + data );
        }
        return xml;
    },

先对参数进行判断,然后用了一个try catch ,这个try catch 主要是对Ie9进行支持的,因为在ie9中,如果传入的xml字符串不合法的话,那么在ie9中直接报错,其他浏览器则不会报错,直接返回一个parseerror的节点,所以用try进行处理,

另外DOMParser方法,现在的大部分浏览器都支持,iE8及以下不支持,所以这里进行转换,直接是调用这个方法进行转换的。

最后进行判断,如果报错,则抛出错误信息。

noop:方法

这个方法就是一个空方法,源码:

noop: function() {},

这个空方法在做插件扩展的时候可能会用到。例如:

        function Sa() {
            this.default = {
                fun:$.noop()
            }
        }

        Sa.prototype.init = function (opt) {
            $.extend(this.default, opt);
        }

有是在给默认属性的时候,会用到空方法,所以大部分的应用是做这个的。

源码:

noop: function() {},

globalEval:方法

这个方法是创建全局变量的,例如:

        function test() {
            eval('var a=5');
            console.log(a); //5;
            $.globalEval('var b=7');
            console.log(b); //7;
        }
        test();
        console.log(a); //aught ReferenceError: a is not defined;
        console.log(b); //7;

可以看到通过一般的eval进行声明的,只是声明了局部变量,而通过jQuery,则在声明的是全局变量。源码如下:

// Evaluates a script in a global context
    globalEval: function( code ) {
        var script,
                indirect = eval;

        code = jQuery.trim( code );

        if ( code ) {
            // If the code includes a valid, prologue position
            // strict mode pragma, execute code by injecting a
            // script tag into the document.
            if ( code.indexOf("use strict") === 1 ) {
                script = document.createElement("script");
                script.text = code;
                document.head.appendChild( script ).parentNode.removeChild( script );
            } else {
            // Otherwise, avoid the DOM node creation, insertion
            // and removal by using an indirect global eval
                indirect( code );
            }
        }
    },

先对参数进行去空格,然后进行判断是否在严格模式下运行,因为严格模式是禁止用eval方法的,当为严格模式的时候,可以看到,内部其实是在head中添加了一个script标签,把传入的代码附加到里面,进行声明之后,在将这个script标签移除,

这样声明的变量就存在全局作用域中了,如果非严格模式下,直接用eval方法进行解析就可以了,但是这里可以看到这个细节,将eval赋值给了声明的变量indirect中,这样做是因为eval有两种,一种是关键字,一种是window下的属性,这样赋值

就是代表调用的window下的属性方法,所以在全局都可以找到,如果只用eval进行解析,那么就会认为是关键字,自然就是局部变量了。

camelCase方法:

这个方法是将传入的参数进行驼峰转换的,因为在代码中并不能对margin-top这种新式的属性进行解析,将margin-top转换为:marginTop这种形式:

        var str = 'margin-top';
        console.log($.camelCase(str)); //marginTop

源码如下:

// Convert dashed to camelCase; used by the css and data modules
    // Microsoft forgot to hump their vendor prefix (#9572)
    camelCase: function( string ) {
        return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
    },

代码中可以看到第一个replace是对ms进行处理,RMSPrefix正则是对-ms-进行匹配,将-ms-替换成ms- 这样在进行转换就可以了,因为IE的前缀是msTransForm,第一个字母小写,而火狐等则是MozTransForm,第一个字母大写,所以如果是

-ms-开头的,先进行替换,然后在进行下面的转换。rdashAlpha是对 - 和后面的字母或数字进行匹配,然后调用facmelCase回调方法,进行转换为大写。

// Used by jQuery.camelCase as callback to replace()
    fcamelCase = function( all, letter ) {
        return letter.toUpperCase();
    },

nodeName方法:

这个方法是判断节点名和传入的字符串是否相等,例如:

  console.log($.nodeName(document.documentElement, 'html')); //true

源码:

nodeName: function( elem, name ) {
        return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
    },

源码没什么特别的,只是需要将nodeName转换成小写,因为在不同浏览器中的nodeName可能大小写不一致。

原文地址:https://www.cnblogs.com/y8932809/p/5887563.html