logo头像

求知若渴,虚心若愚

jQuery - jQuery源码学习 - jQuery扩展工具方法源码分析(四)

noop()

  • 一个空函数
  • 此方法不接受任何参数
  • 当某些时候你需要传入函数参数,而且希望它什么也不做的时候,你可以使用该函数,也无需再新建一个空的函数
  • 比如当插件提供了一个可选的回调函数接口,那么如果调用的时候没有传递这个回调函数,就用$.noop来代替执行。

globalEval()

  • 将变量转为全局变量
  • 实际就是全局的eval()函数,并且做了兼容处理
  • eval()函数

    • eval()函数执行一段JavaScript代码字符串,只有直接使用eval()本身,会在当前作用域中执行代码,否则相当于在全局作用域中执行代码。

      • 直接使用eval()本身,相当于在当前作用域执行代码
      • 通过window.eval(),代码将在全局作用域执行
      • 将eval赋值给其他变量,间接使用,代码将在全局作用域执行

      • eval()函数在严格模式下:

        • eval中的代码不能创建eval所在作用域下的变量、函数。
        • 而是为eval单独创建一个作用域,即严格模式创设了第三种作用域:eval作用域,并在eval返回时丢弃
        • 严格模式下,间接使用:没有eval作用域,仍是全局作用域执行
        • 在严格模式下,通过window调用,没有eval作用域

TIP
严格模式只对直接使用eval()有效,对间接使用的eval()无效

jQuery中的工具方法globalEval(),无论在什么条件下,都在全局作用域中执行代码

其实就是:将变量转为全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Evaluates a script in a global context
globalEval: function( code ) {
var script,
indirect = eval;
// eval既是关键字,又是window下的属性。直接写eval(code),浏览器会当做js关键字使用,出错。所以赋值一下,就会把eval当做window的属性

//code必须为字符串形式
code = jQuery.trim( code );

if ( code ) {
// 严格模式下,不能使用eval
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 );
}
}
},

camelCase()

  • 转换连字符式的字符串为驼峰式
  • 用于CSS模块和数据缓存模块
  • Camel-Case:骆驼命名法
1
2
3
4
5
6
7

rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
// fcamelCase:把字符串转换为大写,返回一个新的字符串
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
  • 正则rdashAlpha用于匹配字符串中连字符“-”和其后的第一个字母或数字。
  • 如果连字符“-”后是字母,则匹配部分会被替换为对应的大写字母;如果连字符“-”后是数字,则会删掉连字符“-”,保留数字。

  • 正则rmsPrefix用于匹配字符串中前缀“-ms-”,匹配部分会被替换为“ms-”。

  • 这么做是因为在IE中,连字符式的样式名前缀“-ms-”对应小写的“ms”,而不是驼峰式的“Ms”。
  • 例如,“-ms-transform”对应“msTransform”而不是“MsTransform”。在IE以外的浏览器中,连字符式的样式名则可以正确地转换为驼峰式,例如,“-moz-transform”对应“MozTransform”。

nodeName()

  • 用于检查DOM元素的节点名称(即属性nodeName)与指定的值是否相等
  • 检查时忽略大小写
1
2
3
4

nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
  • 前先检查elem.nodeName是否存在,可以防止传递进来的不是DOM元素,或者元素没有nodeName引起的报错问题
  • 把属性elem.nodeName和参数name都转换为大写再做比较,也就是忽略大小写比较
    • DOM元素的属性nodeName返回该元素的节点名称
    • 对于HTML文档,始终返回其大写形式
    • 对于XML文档,因为XML文档区分大小写,所以返回值与源代码中的形式一致。

each()

  • jQuery的工具方法,其实就是静态方法,本方法是$.each()

    • 注意jquery的$().each,$.each的区别
    • $().each

      • 该方法用于遍历jQuery对象
      • 本质调用的是$.each
      • each() 方法规定为每个匹配元素规定运行的函数。
      • 回调函数中的this不是jQuery对象 而是Dom对象
    • $.each

      • 该方法用于遍历任何集合,包括数组和对象
      • 对于jQuery对象,只是把each方法简单的进行了委托
        • 把jQuery对象作为第一个参数传递给jQuery的each方法
        • 也就是jQuery提供的each方法是对参数一提供的对象的中所有的子元素逐一进行方法调用
      • jQuery里的each方法是通过js里的call方法来实现的
        • call:改变上下文this指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

each: function( obj, callback, args ) {
var value,
i = 0,
length = obj.length,
// 是否是类数组或数组,json(不包括jQuery这种对象形式)返回false
isArray = isArraylike( obj );

if ( args ) { //jQuery内部使用
if ( isArray ) { // 如果是类数组
for ( ; i < length; i++ ) {
value = callback.apply( obj[ i ], args );

if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.apply( obj[ i ], args );

if ( value === false ) {
break;
}
}
}

// A special, fast, case for the most common use of each
} else { // 我们在外面调用时,执行的代码
if ( isArray ) { // 如果是类数组
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
// 回调方法返回false就停止循环
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) { // //如果是json对象
value = callback.call( obj[ i ], i, obj[ i ] );

if ( value === false ) {
break;
}
}
}
}

return obj;
},
  • 第三个参数args用于内部调用
  • 此方法就是来遍历数组的,然后取数组中的值进行显示。
  • 不能改变原数组arr,跟map一样,但是map返回新数组,而each返回原数组。
  • 这里跟原生的forEach和map的回调方法参数不一样,原生的回调方法中,第三个参数是原数组,可以在回调方法中改变原数组的值。但jQuery的回调方法,不会传第三个参数。
支付宝打赏 微信打赏

赞赏是对我们的肯定!