天天看点

jQuery源码中的一些细节分析(一)

!!的使用

var length = !!obj && "length" in obj && obj.length
           

这是jQuery里的isArrayLike函数里的一句话,用来返回该函数的参数obj是否有length属性,如果有length属性的值是多少。需要注意的是在这个一连串的判断中第一个判断条件用了!!obj而不是obj。

其实两者的作用类似,都是为了排除obj是undefined、null、NaN等六种为false的情况,但是这里选择了使用!!obj的原因是什么呢?我们需要联系下面的代码来看:

return type === "array" || length === 0 ||typeof length === "number" && length > 0 && ( length - 1 ) in obj;
           

这一串代码就是这个函数的返回值,里面有一个length === 0的判断,也就是判断如果这个obj为一个空数组[ ]或者是一个只有一个length属性并且为0的时候就可以返回true。但是如果在前面使用了obj而不是!!obj,那么当obj为0的时候length的值将会也为0,这里的判断就会有问题。

function isArrayLike()的一些问题

var length = !!obj && "length" in obj && obj.length,
		type = toType( obj );

	if ( isFunction( obj ) || isWindow( obj ) ) {
		return false;
	}

	return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
           

这是jQuery的函数的源代码,就是上面提到的函数,主要有两个问题:

关于数据类型

"length" in obj

,这个语句在应用到“ ”定义的字符串的时候会报错:Typeerror:cannot use ‘in’ operator to search……这主要是因为in操作符要求右端为对象,而“”定义字符串并不是一个字符串对象,相对的如果是使用new String定义的就没有问题。

考虑全部可能

return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj
           

这个语句在遇到obj={length:0,……},这样的length属性为零但仍有其他属性值存在的时候仍然会判断为true。

关于CSS编码问题

funescape = function( _, escaped, escapedWhitespace ) {
	//需要判断该16进制数是遵循UTF-8标准(默认)还是其他的标准。
		var high = "0x" + escaped - 0x10000;
		// NaN means non-codepoint
		// Support: Firefox<24
		// Workaround erroneous numeric interpretation of +"0x"
		return high !== high || escapedWhitespace ?
			escaped :
			high < 0 ?
				// BMP codepoint
				String.fromCharCode( high + 0x10000 ) :
				// Supplemental Plane codepoint (surrogate pair)
				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
	},
           

这里是Sizzle引擎里面的一个小函数。主要的功能是将以“/”开头的特殊16进制符号编码转换为为对应的字符串。出现这样一个函数的原因主要是因为W3C标准允许在CSS中使用\开头的十六进制数(最多六位)来表示一些特殊符号,如果不足六位的话,该十六进制数应当以任何形式的空白符结尾。如果知道这个的话再去看上面的一个正则表达式就会很容易理解:

runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" )
           

它其实就是负责筛选这些特殊符号。

但是把这个函数单独提出来并不是为了去理解这个正则而是为了理解两个东西:一是Unicode和[ISO10646]字符集与UTF-8、UTF-16、UTF-32等等编码标准的关系;二是编码转换的规则。

字符集与编码规则

Unicode和[ISO10646]字符集定义了文字和二进制的对应关系,为字符分配了唯一的编号,而UTF-8、UTF-16、UTF-32就是选择具体的编码方案去存储这些内存编号,这也是为什么在我们打开文档时如果字符编码选择错即使都是Unicode编码仍然会出现乱码的原因。

目前最常用的编码就是UTF-8(也是HTML文档默认编码,似乎也是唯二的一个可以兼容ASCII编码的)。但是在一些特殊情况下可以由开发者指定特殊的编码方案,所以就出现了上面的函数里在返回时的一系列判断。

编码转换

这个话题在前端开发里面似乎并不常见,但是在嵌入式开发里全是极其的普遍。

很简单的一个例子:char a = “1”与int b = 1是不相等的,因为char a的1就是对应编码规则表示的1,而b的1就是1。在嵌入式开发中尤其在串口通讯的时候需要注意的是在一些情况下串口会自动将传过来的字符按照ASCII码的规则去转义,这时你去传一个int 1那你接受到的就会是0x01对应的ASCII码了。如果你想打印出来也是1也很简单,用接受到的值(一般是char或者是unsigned char)加上“0”就完成了转换了。