jquery TypeError: U[a].exec is not a function 是咋个回事
这个是jquery构造的问题,jquery官方非常多的提醒过这个,就是不要随便用prototype,会影响到jquery的遍历。
children的实现是一个遍历,你自定义了一个prototype,于是jquery就会遍历到这个,但你这个又是个函数,而不是一个jquery对象
而当你使用("#question_box p") 在jq内部就不是遍历来实现的,而是find
find的实现
find:
function
( selector ) {
// 当表达式不包含“,”符号时候
if
(
this
.length === 1 && !/,/.test(selector) ) {
var
ret =
this
.pushStack( [],
"find"
, selector );
ret.length = 0;
jQuery.find( selector,
this
[0], ret );
return
ret;
}
// 当表达式包含“,”符号时候
else
{
var
elems = jQuery.map(
this
,
function
(elem){
return
jQuery.find( selector, elem );
});
return
this
.pushStack( /[^+>] [^+>]/.test( selector ) ?
jQuery.unique( elems ) :
elems,
"find"
, selector );
}
}
//其中的jQuery.find是这样一个方法:
jQuery.find = Sizzle.find;
//而sizzle又是这样一个方法:
var
Sizzle =
function
(selector, context, results, seed) {
results = results || [];
context = context || document;
if
( context.nodeType !== 1 && context.nodeType !== 9 )
return
[];
if
( !selector ||
typeof
selector !==
"string"
) {
return
results;
}
var
parts = [], m, set, checkSet, check, mode, extra, prune =
true
;
// Reset the position of the chunker regexp (start from head)
chunker.lastIndex = 0;
while
( (m = chunker.exec(selector)) !==
null
) {
parts.push( m[1] );
if
( m[2] ) {
extra = RegExp.rightContext;
break
;
}
}
if
( parts.length > 1 && origPOS.exec( selector ) ) {
if
( parts.length === 2 && Expr.relative[ parts[0] ] ) {
set = posProcess( parts[0] + parts[1], context );
}
else
{
set = Expr.relative[ parts[0] ] ?
[ context ] :
Sizzle( parts.shift(), context );
while
( parts.length ) {
selector = parts.shift();
if
( Expr.relative[ selector ] )
selector += parts.shift();
set = posProcess( selector, set );
}
}
}
else
{
var
ret = seed ?
{ expr: parts.pop(), set: makeArray(seed) } :
Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
set = Sizzle.filter( ret.expr, ret.set );
if
( parts.length > 0 ) {
checkSet = makeArray(set);
}
else
{
prune =
false
;
}
while
( parts.length ) {
var
cur = parts.pop(), pop = cur;
if
( !Expr.relative[ cur ] ) {
cur =
""
;
}
else
{
pop = parts.pop();
}
if
( pop ==
null
) {
pop = context;
}
Expr.relative[ cur ]( checkSet, pop, isXML(context) );
}
}
if
( !checkSet ) {
checkSet = set;
}
if
( !checkSet ) {
throw
"Syntax error, unrecognized expression: "
+ (cur || selector);
}
if
( toString.call(checkSet) ===
"[object Array]"
) {
if
( !prune ) {
results.push.apply( results, checkSet );
}
else
if
( context.nodeType === 1 ) {
for
(
var
i = 0; checkSet[i] !=
null
; i++ ) {
if
( checkSet[i] && (checkSet[i] ===
true
|| checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
results.push( set[i] );
}
}
}
else
{
for
(
var
i = 0; checkSet[i] !=
null
; i++ ) {
if
( checkSet[i] && checkSet[i].nodeType === 1 ) {
results.push( set[i] );
}
}
}
}
else
{
makeArray( checkSet, results );
}
if
( extra ) {
Sizzle( extra, context, results, seed );
}
return
results;
};
|
而children的实现方法如下(children就是“>”)
relative: {
//
">"
:
function
(checkSet, part, isXML){
// 当part为单词字符时,如$("form > input"),part为“form”
if
(
typeof
part ===
"string"
&& !/\W/.test(part) ) {
part = isXML ? part : part.toUpperCase();
for
(
var
i = 0, l = checkSet.length; i < l; i++ ) {
var
elem = checkSet[i];
if
( elem ) {
// 得到elem的父节点
var
parent = elem.parentNode;
// 如果父节点名称为part值时,在checkSet[i]上赋值父节点,否则赋值false
checkSet[i] = parent.nodeName === part ? parent :
false
;
}
}
// 当part为非单词字符时,如$(".blue > input"),part为“.blue”
}
else
{
for
(
var
i = 0, l = checkSet.length; i < l; i++ ) {
var
elem = checkSet[i];
if
( elem ) {
checkSet[i] =
typeof
part ===
"string"
?
elem.parentNode :
elem.parentNode === part;
}
}
if
(
typeof
part ===
"string"
) {
Sizzle.filter( part, checkSet,
true
);
}
}
},
}
|
看出区别了吗?用的是Sizzle.filter
说道Sizzle,那是相当牛的一个选择器引擎,find和filter是其核心方法之一,他们的区别可以看这个:
http://www.cnblogs.com/xesam/archive/2012/02/15/2352574.html
http://www.cnblogs.com/xesam/archive/2012/02/18/2356617.html
其中跟你的问题有关的段落摘录如下:
find直接用原生的getElementById(当然也会用byname或者其他)去找
Expr.find = {
ID:
function
( match, context, isXML ) {
if
(
typeof
context.getElementById !==
"undefined"
&& !isXML ) {
var
m = context.getElementById(match[1]);
return
m && m.parentNode ? [m] : [];
}
},
//byclass by name是一样的实现
|
而children因为只找子一级,不再往下找,所以采取的是两次过滤的方法,即过滤questionbox的下一级元素,然后再看是不是p标签,(在jq的1.2以后的版本里,这个过程是反过来的,似乎,即先找出所有p,然后再看父元素是不是你前一个筛选器,这个机制我记不太清了,懒得去翻源代码看了,你有兴趣可以研究下)
那么,这时候就要用到for in循环,而这时候你又给所有对象定义了新的属性,所以for in的时候必然遍历到你这个新属性,你这个自定义的属性又不是个jq对象,于是自然杯具了。
但奇特的是,我反复测试了你的代码,发现在jq2.0以后的版本上似乎是没问题的。。。难道jq改了选择器的实现?
不太清楚了 我将我页面上的 jquery 改成了2.1.1版本 还是有这个问题 除非去掉那个 原型的定义
嗯 总之最好不要这样用。 也可能是你别的一些方法影响了jq