Reputation: 3490
In pure JavaScript, I am trying to make the jQuery.each
function. So far I have just copied parts from the query source code.
Here is what I have so far:
var class2type = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object",
"[object Error]": "error"
},
core_toString = class2type.toString;
function type(obj) {
if (obj == null) {
return String(obj);
}
return typeof obj === "object" || typeof obj === "function" ? class2type[core_toString.call(obj)] || "object" : typeof obj;
}
function isWindow(obj) {
return obj != null && obj == obj.window;
}
function isArraylike(obj) {
var length = obj.length,
type = type(obj);
if (isWindow(obj)) {
return false;
}
if (obj.nodeType === 1 && length) {
return true;
}
return type === "array" || type !== "function" && (length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj);
}
function each( obj, callback, args ) {
var value,
i = 0,
length = obj.length,
isArray = isArraylike( obj );
if ( args ) {
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;
}
}
}
} else {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
}
}
return obj;
}
It should work fine, but when I I try to run the following code:
each([1, 2], function( index, value ) {
alert( index + ": " + value );
});
I get the following error: TypeError: 'undefined' is not a function (evaluating 'type(obj)') This refers to here:
23| function isArraylike(obj) {
24| var length = obj.length,
25| type = type(obj);
Why won't this code work? I just used parts directly from jQuery's source code.
Thank you.
Upvotes: 1
Views: 1240
Reputation: 27823
The problem is one of variable hoisting and shadowing. You have a type
function outside of the current scope and you expect that in the statement on line 25 it is the one used as a function and then the result is passed to the local variable with the same name:
function type () {};
function isArraylike(){
var type = type(1);
};
In fact, what the code looks like due to variable hoisting is:
function type() {};
function isArraylike(){
var type; // type is undefined here
type = type(1);
};
So you can see that throughout the isArraylike
function, type
will always be a variable and it will never reference the function from the outer scope. The fix is simple: use another name either for the function or the variable.
Upvotes: 3