• 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可能大小写不一致。

  • 相关阅读:
    小毛病,大问题
    [zz]Libvirt 虚拟化库剖析
    libvirt XML 学习笔记
    Ubuntu 10.04下使用 libvirt 创建KVM虚拟机
    [zz]使用libvirt管理kvm虚拟机(更新中)
    [zz]LXC:Linux 容器工具
    一些比较好的URL
    [zz]Libvirt XML学习笔记
    [zz]一些KVM xml 例子
    [zz]kvm环境使用libvirt创建虚拟机
  • 原文地址:https://www.cnblogs.com/y8932809/p/5887563.html
Copyright © 2020-2023  润新知